macaddr 64 bit (EUI-64) datatype support

Started by Haribabu Kommiover 9 years ago73 messages
#1Haribabu Kommi
kommi.haribabu@gmail.com
1 attachment(s)

There was bug that is raised in [1]/messages/by-id/20161010162001.1413.12486@wrigleys.postgresql.org related to storing EUI-64 mac address
in PostgreSQL MAC address datatype.

As the current macaddr datatype stores only 48 bit MAC address only, and
now a days
people are adopting to EUI-64 format of MAC address. So it better to add
the support
in PostgreSQL.

Here I attached a POC patch that adds the support for EUI-64 MAC address
storage with a
new datatype macaddr64. Currently this type takes only EUI-64 datatype, not
accepts 48
bit MAC address.

Before continuing and adding more details for macaddr64 datatype, it is not
possible to
add the support for current macaddr datatype as it is a fixed size datatype
that is stored
in the disk. So any enhancements to change it from 48 to 64 bit will give
problems to
pg_upgrade.

As we are moving to PostgreSQL 10, so are there any plans of backward
compatiblity
breakage, so the existing macaddr datatype itself can be changed to support
both
48 and 64 bit MAC addresses. If not, I will try update the POC patch with
more details
similar like macaddr datatype.

[1]: /messages/by-id/20161010162001.1413.12486@wrigleys.postgresql.org
/messages/by-id/20161010162001.1413.12486@wrigleys.postgresql.org

Regards,
Hari Babu
Fujitsu Australia

Attachments:

macaddr64_poc.patchapplication/octet-stream; name=macaddr64_poc.patchDownload
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..70f7368 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac64.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac64.c b/src/backend/utils/adt/mac64.c
new file mode 100644
index 0000000..b11b6eb
--- /dev/null
+++ b/src/backend/utils/adt/mac64.c
@@ -0,0 +1,353 @@
+/*
+ *	PostgreSQL type definitions for 64 bit MAC addresses (EUI-64).
+ *
+ *	src/backend/utils/adt/mac64.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)|((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24)|((addr)->f<<16)|((addr)->g<<8)|((addr)->h)))
+
+/*
+ *	MAC address (EUI-64) reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr64_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr64    *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%2x%2x%2x%2x-%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+	if (count != 8)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+
+	if (count != 8)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					errmsg("invalid input syntax for type macaddr64: \"%s\"", str)));
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid octet value in \"macaddr64\" value: \"%s\"", str)));
+
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr64\" Address: \"%s\"", str),
+			   errhint ("00-00-00-00-00-00-00-00 address is a reserved address")));
+
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr64\" Address: \"%s\"", str),
+			   errhint ("FF-FF-FF-FF-FF-FF-FF-FF address is a reserved address")));
+
+	result = (macaddr64 *) palloc(sizeof(macaddr64));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR64_P(result);
+}
+
+/*
+ *	MAC address output function.  Fixed format.
+ */
+
+Datum
+macaddr64_out(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr = PG_GETARG_MACADDR64_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d, addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *		macaddr64_recv			- converts external binary format to macaddr(EUI-64)
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr64_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr64    *addr;
+
+	addr = (macaddr64 *) palloc(sizeof(macaddr64));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+	addr->d = pq_getmsgbyte(buf);
+	addr->e = pq_getmsgbyte(buf);
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR64_P(addr);
+}
+
+/*
+ *		macaddr64_send			- converts macaddr(EUI-64) to binary format
+ */
+Datum
+macaddr64_send(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr = PG_GETARG_MACADDR64_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr64_cmp_internal(macaddr64 *a1, macaddr64 *a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr64_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_INT32(macaddr64_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr64_lt(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr64_le(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr64_eq(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr64_ge(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr64_gt(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr64_ne(PG_FUNCTION_ARGS)
+{
+	macaddr64    *a1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *a2 = PG_GETARG_MACADDR64_P(1);
+
+	PG_RETURN_BOOL(macaddr64_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr64.
+ */
+Datum
+hashmacaddr64(PG_FUNCTION_ARGS)
+{
+	macaddr64    *key = PG_GETARG_MACADDR64_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr64));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr64_not(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *result;
+
+	result = (macaddr64 *) palloc(sizeof(macaddr64));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+	PG_RETURN_MACADDR64_P(result);
+}
+
+Datum
+macaddr64_and(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *addr2 = PG_GETARG_MACADDR64_P(1);
+	macaddr64    *result;
+
+	result = (macaddr64 *) palloc(sizeof(macaddr64));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+	PG_RETURN_MACADDR64_P(result);
+}
+
+Datum
+macaddr64_or(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr1 = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *addr2 = PG_GETARG_MACADDR64_P(1);
+	macaddr64    *result;
+
+	result = (macaddr64 *) palloc(sizeof(macaddr64));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+	PG_RETURN_MACADDR64_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing mac manufacturers.
+ *	From suggestion by Alex Pilosov <alex@pilosoft.com>
+ */
+Datum
+macaddr64_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr64    *addr = PG_GETARG_MACADDR64_P(0);
+	macaddr64    *result;
+
+	result = (macaddr64 *) palloc(sizeof(macaddr64));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->d;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->g = 0;
+
+	PG_RETURN_MACADDR64_P(result);
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6b52222..21372af 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -695,6 +695,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr64	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr64 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2114,6 +2116,28 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr64 type support */
+DATA(insert OID = 3349 (  macaddr64_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr64_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3350 (  macaddr64_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr64_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 3351 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr64_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR64 manufacturer fields");
+
+DATA(insert OID = 3352 (  macaddr64_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3353 (  macaddr64_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_lt _null_ _null_ _null_ ));
+DATA(insert OID = 3354 (  macaddr64_le			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_le _null_ _null_ _null_ ));
+DATA(insert OID = 3355 (  macaddr64_gt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_gt _null_ _null_ _null_ ));
+DATA(insert OID = 3356 (  macaddr64_ge			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_ge _null_ _null_ _null_ ));
+DATA(insert OID = 3357 (  macaddr64_ne			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_ne _null_ _null_ _null_ ));
+DATA(insert OID = 3358 (  macaddr64_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr64_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 3359 (  macaddr64_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr64_not _null_ _null_ _null_ ));
+DATA(insert OID = 3360 (  macaddr64_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr64_and _null_ _null_ _null_ ));
+DATA(insert OID = 3361 (  macaddr64_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr64_or _null_ _null_ _null_ ));
+
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4046,6 +4070,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr64_recv	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr64_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr64_send	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr64_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 162239c..4c957fe 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,9 +441,13 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr64    PGNSP PGUID	8 f b U f t \054 0 0 775 macaddr64_in macaddr64_out macaddr64_recv macaddr64_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR64OID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -482,6 +486,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr64 PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 2ae212a..4e85fbd 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1022,6 +1022,24 @@ extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
+/* mac64.c */
+extern Datum macaddr64_in(PG_FUNCTION_ARGS);
+extern Datum macaddr64_out(PG_FUNCTION_ARGS);
+extern Datum macaddr64_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr64_send(PG_FUNCTION_ARGS);
+extern Datum macaddr64_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr64_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr64_le(PG_FUNCTION_ARGS);
+extern Datum macaddr64_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr64_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr64_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr64_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr64_not(PG_FUNCTION_ARGS);
+extern Datum macaddr64_and(PG_FUNCTION_ARGS);
+extern Datum macaddr64_or(PG_FUNCTION_ARGS);
+extern Datum macaddr64_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr64(PG_FUNCTION_ARGS);
+
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
 extern Datum numeric_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 9fd954d..5342d19 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC addresses (EUI-64):
+ */
+typedef struct macaddr64
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr64;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -115,6 +130,11 @@ typedef struct macaddr
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
+/* macaddr64 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr64P(X)    ((macaddr64 *) DatumGetPointer(X))
+#define Macaddr64PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR64_P(n) DatumGetMacaddr64P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR64_P(x) return Macaddr64PGetDatum(x)
 
 /*
  * Support functions in network.c
#2Michael Paquier
michael.paquier@gmail.com
In reply to: Haribabu Kommi (#1)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Oct 12, 2016 at 3:30 PM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:

As we are moving to PostgreSQL 10, so are there any plans of backward
compatiblity
breakage, so the existing macaddr datatype itself can be changed to support
both
48 and 64 bit MAC addresses.

Er, I had thought that we should not use Postgres 10 as a reason for
backward-incompatible breakages, at least not to increase them into a
such amount that upgrading would be a pain.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Craig Ringer
craig@2ndquadrant.com
In reply to: Haribabu Kommi (#1)
Re: macaddr 64 bit (EUI-64) datatype support

On 12 October 2016 at 14:30, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

As we are moving to PostgreSQL 10, so are there any plans of backward
compatiblity
breakage, so the existing macaddr datatype itself can be changed to support
both
48 and 64 bit MAC addresses. If not, I will try update the POC patch with
more details
similar like macaddr datatype.

There's been some minor BC breaking, but breaking on-disk format for
pg_upgrade is a much bigger deal. I'm really not a fan of that idea.

Just use macaddr64 if you want wide MACs.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Julien Rouhaud
julien.rouhaud@dalibo.com
In reply to: Craig Ringer (#3)
Re: macaddr 64 bit (EUI-64) datatype support

On 12/10/2016 09:32, Craig Ringer wrote:

On 12 October 2016 at 14:30, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

As we are moving to PostgreSQL 10, so are there any plans of backward
compatiblity
breakage, so the existing macaddr datatype itself can be changed to support
both
48 and 64 bit MAC addresses. If not, I will try update the POC patch with
more details
similar like macaddr datatype.

There's been some minor BC breaking, but breaking on-disk format for
pg_upgrade is a much bigger deal. I'm really not a fan of that idea.

Just use macaddr64 if you want wide MACs.

+1

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

--
Julien Rouhaud
http://dalibo.com - http://dalibo.org

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Julien Rouhaud (#4)
Re: macaddr 64 bit (EUI-64) datatype support

Julien Rouhaud wrote:

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

Having macaddr64 support both formats sounds nice, but how does it work?
Will we have to reserve one additional bit to select the representation?
That would make the type be 65 bits which is a clear loser IMO.

Is it allowed to just leave 16 bits as zeroes which would indicate that
the address is EUI48? I wouldn't think so ...

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Haribabu Kommi (#1)
Re: macaddr 64 bit (EUI-64) datatype support

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Here I attached a POC patch that adds the support for EUI-64 MAC address
storage with a new datatype macaddr64. Currently this type takes only
EUI-64 datatype, not accepts 48 bit MAC address.

Our other data types that have sizes in the names measure the sizes in
bytes (float4, int8, etc). Should this be called macaddr8?

As we are moving to PostgreSQL 10, so are there any plans of backward
compatiblity breakage, so the existing macaddr datatype itself can be
changed to support both 48 and 64 bit MAC addresses.

As others have noted, there is no likelihood that we'd take a disk-format-
compatibility-breaking patch for v10. Even if we wanted to do that, the
above proposal would also break send/recv (binary COPY) compatibility for
macaddr.

I think that probably the best bet here is to have two types and put some
thought into making them interoperate where appropriate, as the various
sizes of int do. It's kind of a shame that this won't look like the
approach used for inet addresses, but we're stuck.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Julien Rouhaud
julien.rouhaud@dalibo.com
In reply to: Alvaro Herrera (#5)
Re: macaddr 64 bit (EUI-64) datatype support

On 12/10/2016 14:32, Alvaro Herrera wrote:

Julien Rouhaud wrote:

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

Having macaddr64 support both formats sounds nice, but how does it work?
Will we have to reserve one additional bit to select the representation?
That would make the type be 65 bits which is a clear loser IMO.

Is it allowed to just leave 16 bits as zeroes which would indicate that
the address is EUI48? I wouldn't think so ...

From what I read, you can indicate it's an EUI-48 address by storing
FF:FF (or FF:FE for MAC-48) in 4th and 5th bytes of the EUI-64 address.

--
Julien Rouhaud
http://dalibo.com - http://dalibo.org

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Julien Rouhaud (#7)
Re: macaddr 64 bit (EUI-64) datatype support

Julien Rouhaud wrote:

On 12/10/2016 14:32, Alvaro Herrera wrote:

Julien Rouhaud wrote:

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

Having macaddr64 support both formats sounds nice, but how does it work?
Will we have to reserve one additional bit to select the representation?
That would make the type be 65 bits which is a clear loser IMO.

Is it allowed to just leave 16 bits as zeroes which would indicate that
the address is EUI48? I wouldn't think so ...

From what I read, you can indicate it's an EUI-48 address by storing
FF:FF (or FF:FE for MAC-48) in 4th and 5th bytes of the EUI-64 address.

That seems reasonable at first glance; so the new type would be able to
store both 48-bit and 64-bit values, and there would be assignment casts
in both directions and a suite of operators to enable interoperability
of 48-bit values in macaddr8 with values in type macaddr. Right?

(The cast function from macaddr8 to macaddr would raise error if the
4th and 5th bytes are not either FF:FF or FF:FE -- I don't think we can
in practice distinguish EUI-48 from MAC-48 in this context. The cast in
the other direction would have no restriction and should probably always
use FF:FE).

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Alvaro Herrera (#8)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/12/16, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Julien Rouhaud wrote:

On 12/10/2016 14:32, Alvaro Herrera wrote:

Julien Rouhaud wrote:

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

Having macaddr64 support both formats sounds nice, but how does it
work?
Will we have to reserve one additional bit to select the
representation?
That would make the type be 65 bits which is a clear loser IMO.

Is it allowed to just leave 16 bits as zeroes which would indicate that
the address is EUI48? I wouldn't think so ...

From what I read, you can indicate it's an EUI-48 address by storing
FF:FF (or FF:FE for MAC-48) in 4th and 5th bytes of the EUI-64 address.

That seems reasonable at first glance; so the new type would be able to
store both 48-bit and 64-bit values, and there would be assignment casts
in both directions

I think either "macaddr" should be renamed to "macaddr6" (saved its
oid), a new type "macaddr8" is added with introducing a new alias
"macaddr" or the current "macaddr" should accept both versions as the
"inet" type does.

The function "macaddr_recv" can distinguish them by the
StringInfoData.len member, "macaddr_in" - by number of parts split by
":".
The "macaddr_out" and "macaddr_send" can out 6 octets if the stored
value is mapped to MAC-48.
Storing can be done always as 8 bytes using the rule above.

In the other case there is hard from user's PoV to detect at the
design stage when it is necessary to define column as macaddr and when
to macaddr8.
If users need to update a column type (a new hardware appears with
EUI-64 address), they should keep in mind that all things are changed
for the new column type - stored procedure's parameters, application
code interacting with the DB etc.).
I don't agree with Tom's proposal to introduce a new type, it would be
inconvenient for users.

We have types "int2", "int4", "int8" and an alias "int" for a type
"int4", at least psql does not show it:
postgres=# \dT+ int
List of data types
Schema | Name | Internal name | Size | Elements | Owner | Access
privileges | Description
--------+------+---------------+------+----------+-------+-------------------+-------------
(0 rows)

It is understandable to have 3 types for integers because most space
of the DB occupied by them and in the real life we just don't use big
numbers, but cases for "inet" and "macaddr" are different.

and a suite of operators to enable interoperability
of 48-bit values in macaddr8 with values in type macaddr. Right?

(The cast function from macaddr8 to macaddr would raise error if the
4th and 5th bytes are not either FF:FF or FF:FE -- I don't think we can
in practice distinguish EUI-48 from MAC-48 in this context.

The wikipedia says[1]https://en.wikipedia.org/wiki/Organizationally_unique_identifier#48-bit_Media_Access_Control_Identifier_.28MAC-48.29 -- Best regards, Vitaly Burovoy they are the same things but MAC-48 is an
obsolete term for a special case, so there is no necessary to
distinguish them.

The cast in the other direction would have no restriction and should
probably always use FF:FE).

[1]: https://en.wikipedia.org/wiki/Organizationally_unique_identifier#48-bit_Media_Access_Control_Identifier_.28MAC-48.29 -- Best regards, Vitaly Burovoy
--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Vitaly Burovoy (#9)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/12/16, Vitaly Burovoy <vitaly.burovoy@gmail.com> wrote:

On 10/12/16, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Julien Rouhaud wrote:

On 12/10/2016 14:32, Alvaro Herrera wrote:

Julien Rouhaud wrote:

and you can instead make macaddr64 support both format, and provide a
macaddr::macaddr64 cast

Having macaddr64 support both formats sounds nice, but how does it
work?
Will we have to reserve one additional bit to select the
representation?
That would make the type be 65 bits which is a clear loser IMO.

Is it allowed to just leave 16 bits as zeroes which would indicate
that
the address is EUI48? I wouldn't think so ...

From what I read, you can indicate it's an EUI-48 address by storing
FF:FF (or FF:FE for MAC-48) in 4th and 5th bytes of the EUI-64 address.

That seems reasonable at first glance; so the new type would be able to
store both 48-bit and 64-bit values, and there would be assignment casts
in both directions

I think either "macaddr" should be renamed to "macaddr6" (saved its
oid), a new type "macaddr8" is added with introducing a new alias
"macaddr" or the current "macaddr" should accept both versions as the
"inet" type does.

The function "macaddr_recv" can distinguish them by the
StringInfoData.len member, "macaddr_in" - by number of parts split by
":".
The "macaddr_out" and "macaddr_send" can out 6 octets if the stored
value is mapped to MAC-48.
Storing can be done always as 8 bytes using the rule above.

In the other case there is hard from user's PoV to detect at the
design stage when it is necessary to define column as macaddr and when
to macaddr8.
If users need to update a column type (a new hardware appears with
EUI-64 address), they should keep in mind that all things are changed
for the new column type - stored procedure's parameters, application
code interacting with the DB etc.).
I don't agree with Tom's proposal to introduce a new type, it would be
inconvenient for users.

We have types "int2", "int4", "int8" and an alias "int" for a type
"int4", at least psql does not show it:
postgres=# \dT+ int
List of data types
Schema | Name | Internal name | Size | Elements | Owner | Access
privileges | Description
--------+------+---------------+------+----------+-------+-------------------+-------------
(0 rows)

It is understandable to have 3 types for integers because most space
of the DB occupied by them and in the real life we just don't use big
numbers, but cases for "inet" and "macaddr" are different.

and a suite of operators to enable interoperability
of 48-bit values in macaddr8 with values in type macaddr. Right?

(The cast function from macaddr8 to macaddr would raise error if the
4th and 5th bytes are not either FF:FF or FF:FE -- I don't think we can
in practice distinguish EUI-48 from MAC-48 in this context.

The wikipedia says[1] they are the same things but MAC-48 is an
obsolete term for a special case, so there is no necessary to
distinguish them.

The cast in the other direction would have no restriction and should
probably always use FF:FE).

[1]
https://en.wikipedia.org/wiki/Organizationally_unique_identifier#48-bit_Media_Access_Control_Identifier_.28MAC-48.29

Haribabu Kommi, why have you read enough about EUI-64?
Your function "macaddr64_trunc" sets 4 lower bytes as 0 whereas
(according to the Wikipedia, but I can look for a standard) 3 bytes
are still define an OUI (organizationally unique identifier), so
truncation should be done for 5, not 4 lower octets.

The macros "hibits" should be 3 octets long, not 4; "lobits" --- 5 bytes, not 4.
In the other case your comparisons fail.

What document have you used to write the patch? Are short form formats
correct in macaddr64_in?

P.S.: I still think it is a good idea to change storage format,
macaddr_{in,out,send,recv}, fill 4th and 5th bytes if necessary;
change "lobits" macros and add new fields to bit operation functions.
It avoids a new type, casting, comparison functions between macaddr6
and macaddr8 etc. Proposed patch is mostly copy-paste of mac.c

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Vitaly Burovoy (#10)
Re: macaddr 64 bit (EUI-64) datatype support

I'm sorry for the offtopic, but does anyone know a reason why a
condition in mac.c

if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
(e < 0) || (e > 255) || (f < 0) || (f > 255))

can not be rewritten as:

if (((a | b | c | d | e | f) < 0) ||
((a | b | c | d | e | f) > 255))

It seems more compact and a compiler can optimize it to keep a result
of a binary OR for the comparison with 255...

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Tom Lane
tgl@sss.pgh.pa.us
In reply to: Vitaly Burovoy (#10)
Re: macaddr 64 bit (EUI-64) datatype support

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

P.S.: I still think it is a good idea to change storage format,

I'm not sure which part of "no" you didn't understand, but we're
not breaking on-disk compatibility of existing macaddr columns.
Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

If you can think of a way to have one type do it all without breaking
that, then fine; but that seems like a pretty hard problem.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#12)
Re: macaddr 64 bit (EUI-64) datatype support

Tom Lane wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

P.S.: I still think it is a good idea to change storage format,

I'm not sure which part of "no" you didn't understand, but we're
not breaking on-disk compatibility of existing macaddr columns.
Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

I think the suggestion was to rename macaddr to macaddr6 or similar,
keeping the existing behavior and the current OID. So existing columns
would continue to work fine and maintain on-disk compatibility, but any
newly created columns would become the 8-byte variant.

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Tom Lane
tgl@sss.pgh.pa.us
In reply to: Vitaly Burovoy (#11)
Re: macaddr 64 bit (EUI-64) datatype support

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

I'm sorry for the offtopic, but does anyone know a reason why a
condition in mac.c

if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
(e < 0) || (e > 255) || (f < 0) || (f > 255))

can not be rewritten as:

if (((a | b | c | d | e | f) < 0) ||
((a | b | c | d | e | f) > 255))

Well, it's ugly and it adds a bunch of assumptions about arithmetic
behavior that we don't particularly need to make. If this were some
amazingly hot hot-spot then maybe it would be worth making the code
unreadable to save a few nanoseconds, but I doubt that it is.
(Anyway, you've not shown that there actually is any benefit ...)

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#13)
Re: macaddr 64 bit (EUI-64) datatype support

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Tom Lane wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

P.S.: I still think it is a good idea to change storage format,

I'm not sure which part of "no" you didn't understand, but we're
not breaking on-disk compatibility of existing macaddr columns.
Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

I think the suggestion was to rename macaddr to macaddr6 or similar,
keeping the existing behavior and the current OID. So existing columns
would continue to work fine and maintain on-disk compatibility, but any
newly created columns would become the 8-byte variant.

... and would have different I/O behavior from before, possibly breaking
applications that expect "macaddr" to mean what it used to. I'm still
dubious that that's a good idea.

The larger picture here is that we got very little thanks when we squeezed
IPv6 into the pre-existing inet datatype; there's a large number of people
who just said "no thanks" and started using the add-on ip4r type instead.
So I'm not sure why we want to complicate our lives in order to make
macaddr follow the same path.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Tom Lane (#14)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/12/16, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

I'm sorry for the offtopic, but does anyone know a reason why a
condition in mac.c

if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
(e < 0) || (e > 255) || (f < 0) || (f > 255))

can not be rewritten as:

if (((a | b | c | d | e | f) < 0) ||
((a | b | c | d | e | f) > 255))

Well, it's ugly and

it adds a bunch of assumptions about arithmetic
behavior that we don't particularly need to make.

It explains the reason, thank you. I'm just not familiar with other
architectures where it is not the same as in X86/X86-64.

If this were some
amazingly hot hot-spot then maybe it would be worth making the code
unreadable to save a few nanoseconds, but I doubt that it is.

(Anyway, you've not shown that there actually is any benefit ...)

I don't think it has a speed benefit, especially comparing with the sscanf call.
But personally for me the second variant does not seem ugly, just "no
one bit in all variables is out of a byte" (looks better with
comparison with "0xff" as sscanf operates with "%2x").
Sorry for my bad taste and for a noise.

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#10)
Re: macaddr 64 bit (EUI-64) datatype support

On Thu, Oct 13, 2016 at 7:31 AM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

Haribabu Kommi, why have you read enough about EUI-64?
Your function "macaddr64_trunc" sets 4 lower bytes as 0 whereas
(according to the Wikipedia, but I can look for a standard) 3 bytes
are still define an OUI (organizationally unique identifier), so
truncation should be done for 5, not 4 lower octets.

The macros "hibits" should be 3 octets long, not 4; "lobits" --- 5 bytes,
not 4.
In the other case your comparisons fail.

What document have you used to write the patch? Are short form formats
correct in macaddr64_in?

Yes, OUI is 24 bits. I just created prototype patch to check community
opinion on it.
I checked the following links [1]http://standards.ieee.org/develop/regauth/tut/eui64.pdf, [2]https://en.wikipedia.org/wiki/MAC_address for the development of macaddr8. But
the patch is
not correct for all the cases, it is just a prototype to see whether it
accepts 8 byte
MAC address or not?

[1]: http://standards.ieee.org/develop/regauth/tut/eui64.pdf
[2]: https://en.wikipedia.org/wiki/MAC_address

Regards,
Hari Babu
Fujitsu Australia

#18Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Tom Lane (#15)
Re: macaddr 64 bit (EUI-64) datatype support

On Thu, Oct 13, 2016 at 7:59 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Tom Lane wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

P.S.: I still think it is a good idea to change storage format,

I'm not sure which part of "no" you didn't understand, but we're
not breaking on-disk compatibility of existing macaddr columns.
Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

I think the suggestion was to rename macaddr to macaddr6 or similar,
keeping the existing behavior and the current OID. So existing columns
would continue to work fine and maintain on-disk compatibility, but any
newly created columns would become the 8-byte variant.

... and would have different I/O behavior from before, possibly breaking
applications that expect "macaddr" to mean what it used to. I'm still
dubious that that's a good idea.

The larger picture here is that we got very little thanks when we squeezed
IPv6 into the pre-existing inet datatype; there's a large number of people
who just said "no thanks" and started using the add-on ip4r type instead.
So I'm not sure why we want to complicate our lives in order to make
macaddr follow the same path.

Thanks for all your opinions regarding the addition of new datatype to
support
EUI-64 Mac address, I will work on it and come up with a patch.

Regards,
Hari Babu
Fujitsu Australia

#19Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Tom Lane (#15)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/12/16, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Tom Lane wrote:

Vitaly Burovoy <vitaly.burovoy@gmail.com> writes:

P.S.: I still think it is a good idea to change storage format,

I'm not sure which part of "no" you didn't understand,

I just paid attention to the words "likelihood" (mixed up with
"likeliness"), "we wanted" and "probably".
Also there was a note about "would also break send/recv" which
behavior can be saved.
And after your letter Julien Rouhaud wrote about mapping from MAC-48
to EUI-64 which leads absence of a bit indicated version of a stored
value. Which can be considered as a new information.

but we're
not breaking on-disk compatibility of existing macaddr columns.

Can I ask why? It will not be a varlen (typstorage will not be
changed), it just changes typlen to 8 and typalign to 'd'.
For every major release 9.0, 9.1, 9.2 .. 9.6 the docs says "A
dump/restore using pg_dumpall, or use of pg_upgrade, is required".
Both handle changes in a storage format. Do they?

Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

I wrote that for the EUI-48 (MAC-48) values the binary I/O
representation can be saved.
The binary format (in DataRow message) has a length of the column
value which is reflected in PGresAttValue.len in libpq.
If the client works with the binary format it must consult with the
length of the data.
But until the client works with (and columns have) MAC-48 nothing
hurts it and PGresAttValue.len is "6" as now.

I think the suggestion was to rename macaddr to macaddr6 or similar,
keeping the existing behavior and the current OID. So existing columns
would continue to work fine and maintain on-disk compatibility, but any
newly created columns would become the 8-byte variant.

... and would have different I/O behavior from before, possibly breaking
applications that expect "macaddr" to mean what it used to. I'm still
dubious that that's a good idea.

Only if a new type will send xx:xx:xx:FF:FF:xx:xx:xx instead of usual
(expected) 6 octets long.
Again, that case in my offer is similar (by I/O behavior) to "just
change 'macaddr' to keep and accept both MAC-48 and MAC-64", but
allows to use "-k" key for pg_upgrade to prevent rewriting possibly
huge (for instance, 'log') tables (but users unexpectedly get
"macaddr6" after upgrade in their columns and function names which
looks strange enough).

The larger picture here is that we got very little thanks when we squeezed
IPv6 into the pre-existing inet datatype;

Without a sarcasm, I thank a lot all people involved in it because it
does not hurt me (and many other people) from distinguishing ipv4 and
ipv6 at app-level.
I write apps and just save remote address of clients to an "inet"
column named "remote_ip" without thinking "what if we start serving
clients via ipv6?"; or have a column named "allowed_ip" with IPs or
subnets and just save client's IPv4 or IPv6 as a white list (and use
"allowed_ip >>= $1"). It just works.

there's a large number of people
who just said "no thanks" and started using the add-on ip4r type instead.

I found a repository[1]https://github.com/petere/ip4r-cvs at github. From the description it is
understandable why people used ip4r those days (2005 year). The reason
"Furthermore, they are variable length types (to support ipv6) with
non-trivial overheads" is mentioned as the last in its README.
When you deal with IPv4 in 99.999%, storing it in TOAST tables leads
to a big penalty, but the new version of macaddr is not so wide, so it
does not lead to similar speed decrease (it will be stored inplace).

So I'm not sure why we want to complicate our lives in order to make
macaddr follow the same path.

Because according to the Wiki[3]https://en.wikipedia.org/wiki/MAC_address MAC addresses now "are formed
according to the rules of one of three numbering name spaces ...:
MAC-48, EUI-48, and EUI-64.", so IEEE extended range of allowed values
from 48 to 64 bits and since Postgres claims supporting of "mac
addresses", I (as a developer who still uses PG as a primary database)
expect supporting of any kind of mac address, not a limited one. I
expect it is just works.

I reject to imagine what I have to do if I have a column of a type
"macaddr" and unexpectedly I have to deal with an input of EUI-64
type. Add a new column or change columns's type?

In the first case what to do with stored procedures? Duplicate input
parameter to pass the new column of macaddr8 (if macaddr was passed
before)? Duplicate stored procedure?
Also I have to support two columns at the application level. Why? I
just want to store it in the DB, work with it there and get it back!

In the second case (if output will not be mapped to MAC-48 when it is
possible) I have the same troubles as you wrote (oid, I/O and text
representation at least for output, may be also for input).
Moreover I still have to rewrite tables but not when I'm ready for it
(at a migration stage from one major version to another), but when the
task appears.

===
I see no type (besides integers, floats and related with them: their
ranges and arrays ) where numbers appears indicating their capacity:

postgres=# select typname from pg_type where typname ~ '[0-9]' and
typname not like 'pg_toast_%';
typname
-------------
int8
int2
int2vector
int4
float4
float8
_int2
_int2vector
_int4
_int8
_float4
_float8
int4range
_int4range
int8range
_int8range
(16 rows)

So why should we have the name "macaddr" without capacity number and
(unexpectedly) macaddr8 (when a different number appears in the
official name "EAI-64")?

===
I offer a change when the current behavior is not changed for MAC-48
values at all (for textual and binary I/O), internal representation is
always 64bit long, and input and output are mapped from (and when it
is possible to) MAC-48 to seamless usage of a "mac address" concept.

P.S.: Note that the current version[2]https://github.com/RhodiumToad/ip4r of ip4r has the "ipaddress"
type for both IPv4 and IPv6 like the "inet" has. We'll end up having a
single type for both MAC-48 and MAC-64. Why don't do it immediately
(without intermediate types)?
While time passes more and more hardware have EUI-64; the same as more
and more clients have IPv6.

P.P.S.: I played around a length of a value in the binary format (in a
client and in the "macaddr_recv"). It is possible to distinguish
MAC-48 to EUI-64 inputs in "macaddr_recv", so there is no changes
necessary at the client side while it works with the MAC-48 format
only.

[1]: https://github.com/petere/ip4r-cvs
[2]: https://github.com/RhodiumToad/ip4r
[3]: https://en.wikipedia.org/wiki/MAC_address

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#19)
Re: macaddr 64 bit (EUI-64) datatype support

On Thu, Oct 13, 2016 at 4:10 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 10/12/16, Tom Lane <tgl@sss.pgh.pa.us> wrote:

but we're
not breaking on-disk compatibility of existing macaddr columns.

Can I ask why? It will not be a varlen (typstorage will not be
changed), it just changes typlen to 8 and typalign to 'd'.
For every major release 9.0, 9.1, 9.2 .. 9.6 the docs says "A
dump/restore using pg_dumpall, or use of pg_upgrade, is required".
Both handle changes in a storage format. Do they?

macaddr is not a varlena datatype, all the varlena datatypes stores the
length of the data in the header byte because of variable length data
they can hold.

As the macaddr datatype is not that type, so changing the storage size
from 6 to 8 will break the on-disk compatibility, thus it can cause users
to use only pg_dump to upgrade to version 10. pg_upgrade doesn't
handle the changes in storage format.

Just because of a single datatype, loosing the option of using pg_upgrade
is huge and it is not worth as I feel.

Breaking the on-the-wire binary I/O representation seems like a
nonstarter as well.

I wrote that for the EUI-48 (MAC-48) values the binary I/O
representation can be saved.
The binary format (in DataRow message) has a length of the column
value which is reflected in PGresAttValue.len in libpq.
If the client works with the binary format it must consult with the
length of the data.
But until the client works with (and columns have) MAC-48 nothing
hurts it and PGresAttValue.len is "6" as now.

By taking some steps, yes, it is possible to accept both 48-bit and 64-bit
address into a single macaddr datatype.

But I feel this should be done with a new datatype and eventually drop
the old datatype after some time.

===
I see no type (besides integers, floats and related with them: their
ranges and arrays ) where numbers appears indicating their capacity:

postgres=# select typname from pg_type where typname ~ '[0-9]' and
typname not like 'pg_toast_%';
typname
-------------
int8
int2
int2vector
int4
float4
float8
_int2
_int2vector
_int4
_int8
_float4
_float8
int4range
_int4range
int8range
_int8range
(16 rows)

So why should we have the name "macaddr" without capacity number and
(unexpectedly) macaddr8 (when a different number appears in the
official name "EAI-64")?

===
I offer a change when the current behavior is not changed for MAC-48
values at all (for textual and binary I/O), internal representation is
always 64bit long, and input and output are mapped from (and when it
is possible to) MAC-48 to seamless usage of a "mac address" concept.

I agree that adding new datatype whenever the standards are changed to
store the MAC address, instead the new datatype that we are going to add
now can changed as an varlena datatype, so it can handle any length mac
addresses.

The current macaddr datatype needs to be kept for some time by renaming
it without changing OID and use the newer one for further usage.

Regards,
Hari Babu
Fujitsu Australia

#21Shay Rojansky
roji@roji.org
In reply to: Haribabu Kommi (#20)
Re: macaddr 64 bit (EUI-64) datatype support

The current macaddr datatype needs to be kept for some time by renaming
it without changing OID and use the newer one for further usage.

From the point of view of a driver maintainer... Npgsql looks up data types
by their name - upon first connection to a database it queries pg_type and
maps its internal data type handlers based on name. This allows it to avoid
hardcoding data type OIDs in source code, and easily handle user-defined
data types as well (enums, composites...). So a sudden rename of a datatype
would definitely cause a problem. Of course it's possible to first check
the server version and act accordingly but it seems to complicate things
needlessly.

#22Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Tom Lane (#15)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/12/16 4:59 PM, Tom Lane wrote:

The larger picture here is that we got very little thanks when we squeezed
IPv6 into the pre-existing inet datatype; there's a large number of people
who just said "no thanks" and started using the add-on ip4r type instead.

I don't think that is a correct account. People used the ip4r extension
because it was faster, had more functionality, and didn't have those
stupid network masks to worry about. ip4r does in fact also provide a
type that can contain ip4 and ip6, which one ought to use nowadays.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Bruce Momjian
bruce@momjian.us
In reply to: Tom Lane (#6)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Oct 12, 2016 at 08:33:00AM -0400, Tom Lane wrote:

As others have noted, there is no likelihood that we'd take a disk-format-
compatibility-breaking patch for v10. Even if we wanted to do that, the
above proposal would also break send/recv (binary COPY) compatibility for
macaddr.

I think that probably the best bet here is to have two types and put some
thought into making them interoperate where appropriate, as the various
sizes of int do. It's kind of a shame that this won't look like the
approach used for inet addresses, but we're stuck.

If feels like we are going into VARCHAR2 territory where we end up
telling people to use an oddly-named data type forever. Some are
suggesting JSONB is in that category.

I wish I had a suggestion, but I am not above adding trickery to
pg_upgrade to improve the outcome.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ As you are, so once was I.  As I am, so you will be. +
+                      Ancient Roman grave inscription +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Shay Rojansky (#21)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Oct 18, 2016 at 1:51 AM, Shay Rojansky <roji@roji.org> wrote:

The current macaddr datatype needs to be kept for some time by renaming

it without changing OID and use the newer one for further usage.

From the point of view of a driver maintainer... Npgsql looks up data
types by their name - upon first connection to a database it queries
pg_type and maps its internal data type handlers based on name. This allows
it to avoid hardcoding data type OIDs in source code, and easily handle
user-defined data types as well (enums, composites...). So a sudden rename
of a datatype would definitely cause a problem. Of course it's possible to
first check the server version and act accordingly but it seems to
complicate things needlessly.

Yes, that's correct. Changing the existing datatype name is a pain, but for
enhancing
its use to adopt the new hardware addresses, i feel this is required.

Here I attached the first version of patch that supports both EUI-48 and
EUI-64 type
Mac addresses with a single datatype called macaddr. This is an variable
length
datatype similar like inet. It can store both 6 and 8 byte addresses.
Variable length
type is used because in case in future, if MAC address gets enhanced, still
this type
can support without breaking DISK compatibility.

Currently the patch lacks of documentation. Comments?

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_1.patchapplication/octet-stream; name=mac_eui64_support_1.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..a76060f 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -313,14 +313,22 @@ leftmostvalue_interval(void)
 GIN_SUPPORT(interval, false, leftmostvalue_interval, interval_cmp)
 
 static Datum
-leftmostvalue_macaddr(void)
+leftmostvalue_macaddr6(void)
 {
-	macaddr    *v = palloc0(sizeof(macaddr));
+	macaddr6    *v = palloc0(sizeof(macaddr6));
+
+	return Macaddr6PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr6, false, leftmostvalue_macaddr6, macaddr6_cmp)
 
-	return MacaddrPGetDatum(v);
+static Datum
+leftmostvalue_macaddr(void)
+{
+	return DirectFunctionCall1(macaddr_in, CStringGetDatum("00-00-00-00-00-00"));
 }
 
-GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
+GIN_SUPPORT(macaddr, true, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
 leftmostvalue_inet(void)
diff --git a/contrib/btree_gist/btree_macaddr.c b/contrib/btree_gist/btree_macaddr.c
index 87d96c0..c074e95 100644
--- a/contrib/btree_gist/btree_macaddr.c
+++ b/contrib/btree_gist/btree_macaddr.c
@@ -10,8 +10,8 @@
 
 typedef struct
 {
-	macaddr		lower;
-	macaddr		upper;
+	macaddr6		lower;
+	macaddr6		upper;
 	char		pad[4];			/* make struct size = sizeof(gbtreekey16) */
 } macKEY;
 
@@ -30,30 +30,30 @@ PG_FUNCTION_INFO_V1(gbt_macad_same);
 static bool
 gbt_macadgt(const void *a, const void *b)
 {
-	return DatumGetBool(DirectFunctionCall2(macaddr_gt, PointerGetDatum(a), PointerGetDatum(b)));
+	return DatumGetBool(DirectFunctionCall2(macaddr6_gt, PointerGetDatum(a), PointerGetDatum(b)));
 }
 static bool
 gbt_macadge(const void *a, const void *b)
 {
-	return DatumGetBool(DirectFunctionCall2(macaddr_ge, PointerGetDatum(a), PointerGetDatum(b)));
+	return DatumGetBool(DirectFunctionCall2(macaddr6_ge, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
 gbt_macadeq(const void *a, const void *b)
 {
-	return DatumGetBool(DirectFunctionCall2(macaddr_eq, PointerGetDatum(a), PointerGetDatum(b)));
+	return DatumGetBool(DirectFunctionCall2(macaddr6_eq, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
 gbt_macadle(const void *a, const void *b)
 {
-	return DatumGetBool(DirectFunctionCall2(macaddr_le, PointerGetDatum(a), PointerGetDatum(b)));
+	return DatumGetBool(DirectFunctionCall2(macaddr6_le, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 static bool
 gbt_macadlt(const void *a, const void *b)
 {
-	return DatumGetBool(DirectFunctionCall2(macaddr_lt, PointerGetDatum(a), PointerGetDatum(b)));
+	return DatumGetBool(DirectFunctionCall2(macaddr6_lt, PointerGetDatum(a), PointerGetDatum(b)));
 }
 
 
@@ -64,9 +64,9 @@ gbt_macadkey_cmp(const void *a, const void *b)
 	macKEY	   *ib = (macKEY *) (((const Nsrt *) b)->t);
 	int			res;
 
-	res = DatumGetInt32(DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->lower), MacaddrPGetDatum(&ib->lower)));
+	res = DatumGetInt32(DirectFunctionCall2(macaddr6_cmp, Macaddr6PGetDatum(&ia->lower), Macaddr6PGetDatum(&ib->lower)));
 	if (res == 0)
-		return DatumGetInt32(DirectFunctionCall2(macaddr_cmp, MacaddrPGetDatum(&ia->upper), MacaddrPGetDatum(&ib->upper)));
+		return DatumGetInt32(DirectFunctionCall2(macaddr6_cmp, Macaddr6PGetDatum(&ia->upper), Macaddr6PGetDatum(&ib->upper)));
 
 	return res;
 }
@@ -75,7 +75,7 @@ gbt_macadkey_cmp(const void *a, const void *b)
 static const gbtree_ninfo tinfo =
 {
 	gbt_t_macad,
-	sizeof(macaddr),
+	sizeof(macaddr6),
 	16,							/* sizeof(gbtreekey16) */
 	gbt_macadgt,
 	gbt_macadge,
@@ -94,7 +94,7 @@ static const gbtree_ninfo tinfo =
 
 
 static uint64
-mac_2_uint64(macaddr *m)
+mac_2_uint64(macaddr6 *m)
 {
 	unsigned char *mi = (unsigned char *) m;
 	uint64		res = 0;
@@ -127,7 +127,7 @@ Datum
 gbt_macad_consistent(PG_FUNCTION_ARGS)
 {
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
-	macaddr    *query = (macaddr *) PG_GETARG_POINTER(1);
+	macaddr6    *query = (macaddr6 *) PG_GETARG_POINTER(1);
 	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 
 	/* Oid		subtype = PG_GETARG_OID(3); */
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..840a1ee 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac6.o mac.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 509315a..b1ffa1a 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,8 @@
 /*
- *	PostgreSQL type definitions for MAC addresses.
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *  The entire code is written as treating OUI field size as 24 bits
  *
  *	src/backend/utils/adt/mac.c
  */
@@ -11,19 +14,21 @@
 #include "utils/builtins.h"
 #include "utils/inet.h"
 
-
 /*
  *	Utility macros used for sorting and comparing:
  */
 
 #define hibits(addr) \
-  ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
+  ((unsigned long)(((addr)->data[0]<<24)|((addr)->data[1]<<16)|((addr)->data[2]<<8)))
 
 #define lobits(addr) \
-  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+  ((unsigned long)(((addr)->data[3]<<16)|((addr)->data[4]<<8)|((addr)->data[5])))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->data[6]<<8)|((addr)->data[7]))
 
 /*
- *	MAC address reader.  Accepts several common notations.
+ *	MAC address (EUI-48 and EUI-64) reader.  Accepts several common notations.
  */
 
 Datum
@@ -31,58 +36,114 @@ macaddr_in(PG_FUNCTION_ARGS)
 {
 	char	   *str = PG_GETARG_CSTRING(0);
 	macaddr    *result;
+	mac_struct *addr;
 	int			a,
 				b,
 				c,
 				d,
 				e,
-				f;
+				f,
+				g = 0,
+				h = 0;
 	char		junk[2];
 	int			count;
+	bool 		eight_byte_address = false;
 
-	/* %1s matches iff there is trailing non-whitespace garbage */
 
+	/* %1s matches iff there is trailing non-whitespace garbage */
 	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
 				   &a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
 		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
-					   &a, &b, &c, &d, &e, &f, junk);
+				&a, &b, &c, &d, &e, &f, junk);
+
 	if (count != 6)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-			  errmsg("invalid input syntax for type macaddr: \"%s\"", str)));
+	{
+		/* May be a 8-byte MAC address */
+		eight_byte_address = true;
+
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					  errmsg("invalid input syntax for type macaddr: \"%s\"", str)));
+		}
+	}
 
 	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
 		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
-		(e < 0) || (e > 255) || (f < 0) || (f > 255))
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-		   errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
-
-	result = (macaddr *) palloc(sizeof(macaddr));
+			   errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
 
-	result->a = a;
-	result->b = b;
-	result->c = c;
-	result->d = d;
-	result->e = e;
-	result->f = f;
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr\" Address: \"%s\"", str),
+			   errhint ("00-00-00-00-00-00-00-00 address is a reserved address")));
 
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr\" Address: \"%s\"", str),
+			   errhint ("FF-FF-FF-FF-FF-FF-FF-FF address is a reserved address")));
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+	addr = MACADDR(result);
+
+	addr->data[0] = a;
+	addr->data[1] = b;
+	addr->data[2] = c;
+	addr->data[3] = d;
+	addr->data[4] = e;
+	addr->data[5] = f;
+
+	if (eight_byte_address)
+	{
+		addr->data[6] = g;
+		addr->data[7] = h;
+	}
+
+	SET_MACADDR_VARSIZE(result, count);
 	PG_RETURN_MACADDR_P(result);
 }
 
@@ -93,19 +154,26 @@ macaddr_in(PG_FUNCTION_ARGS)
 Datum
 macaddr_out(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr = PG_GETARG_MACADDR_P(0);
+	macaddr    *addr = PG_GETARG_MACADDR_PP(0);
 	char	   *result;
 
 	result = (char *) palloc(32);
 
-	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
-			 addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
+	if (MACADDR_SIZE(addr) == 8)
+		snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				MACADDR(addr)->data[0], MACADDR(addr)->data[1], MACADDR(addr)->data[2],
+				MACADDR(addr)->data[3], MACADDR(addr)->data[4], MACADDR(addr)->data[5],
+				MACADDR(addr)->data[6], MACADDR(addr)->data[7]);
+	else
+		snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
+			 MACADDR(addr)->data[0], MACADDR(addr)->data[1], MACADDR(addr)->data[2],
+			 MACADDR(addr)->data[3], MACADDR(addr)->data[4], MACADDR(addr)->data[5]);
 
 	PG_RETURN_CSTRING(result);
 }
 
 /*
- *		macaddr_recv			- converts external binary format to macaddr
+ *	macaddr_recv - converts external binary format(EUI-48 and EUI-64) to macaddr
  *
  * The external representation is just the six bytes, MSB first.
  */
@@ -115,34 +183,48 @@ macaddr_recv(PG_FUNCTION_ARGS)
 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 	macaddr    *addr;
 
-	addr = (macaddr *) palloc(sizeof(macaddr));
+	addr = (macaddr *) palloc0(sizeof(macaddr));
+
+	MACADDR(addr)->data[0] = pq_getmsgbyte(buf);
+	MACADDR(addr)->data[1] = pq_getmsgbyte(buf);
+	MACADDR(addr)->data[2] = pq_getmsgbyte(buf);
+	MACADDR(addr)->data[3] = pq_getmsgbyte(buf);
+	MACADDR(addr)->data[4] = pq_getmsgbyte(buf);
+	MACADDR(addr)->data[5] = pq_getmsgbyte(buf);
 
-	addr->a = pq_getmsgbyte(buf);
-	addr->b = pq_getmsgbyte(buf);
-	addr->c = pq_getmsgbyte(buf);
-	addr->d = pq_getmsgbyte(buf);
-	addr->e = pq_getmsgbyte(buf);
-	addr->f = pq_getmsgbyte(buf);
+	if (buf->len == 8)
+	{
+		MACADDR(addr)->data[6] = pq_getmsgbyte(buf);
+		MACADDR(addr)->data[7] = pq_getmsgbyte(buf);
+	}
 
+	SET_MACADDR_VARSIZE(addr, buf->len);
 	PG_RETURN_MACADDR_P(addr);
 }
 
 /*
- *		macaddr_send			- converts macaddr to binary format
+ *		macaddr_send			- converts macaddr(EUI-48 and EUI-64) to binary format
  */
 Datum
 macaddr_send(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr = PG_GETARG_MACADDR_P(0);
+	macaddr    *addr = PG_GETARG_MACADDR_PP(0);
 	StringInfoData buf;
 
 	pq_begintypsend(&buf);
-	pq_sendbyte(&buf, addr->a);
-	pq_sendbyte(&buf, addr->b);
-	pq_sendbyte(&buf, addr->c);
-	pq_sendbyte(&buf, addr->d);
-	pq_sendbyte(&buf, addr->e);
-	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, MACADDR(addr)->data[0]);
+	pq_sendbyte(&buf, MACADDR(addr)->data[1]);
+	pq_sendbyte(&buf, MACADDR(addr)->data[2]);
+	pq_sendbyte(&buf, MACADDR(addr)->data[3]);
+	pq_sendbyte(&buf, MACADDR(addr)->data[4]);
+	pq_sendbyte(&buf, MACADDR(addr)->data[5]);
+
+	if (MACADDR_SIZE(addr) == 8)
+	{
+		pq_sendbyte(&buf, MACADDR(addr)->data[6]);
+		pq_sendbyte(&buf, MACADDR(addr)->data[7]);
+	}
+
 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
@@ -154,23 +236,40 @@ macaddr_send(PG_FUNCTION_ARGS)
 static int32
 macaddr_cmp_internal(macaddr *a1, macaddr *a2)
 {
-	if (hibits(a1) < hibits(a2))
+	int 		size1 = MACADDR_SIZE(a1);
+	int 		size2 = MACADDR_SIZE(a2);
+
+	if (hibits(MACADDR(a1)) < hibits(MACADDR(a2)))
 		return -1;
-	else if (hibits(a1) > hibits(a2))
+	else if (hibits(MACADDR(a1)) > hibits(MACADDR(a2)))
 		return 1;
-	else if (lobits(a1) < lobits(a2))
+	else if (lobits(MACADDR(a1)) < lobits(MACADDR(a2)))
 		return -1;
-	else if (lobits(a1) > lobits(a2))
+	else if (lobits(MACADDR(a1)) > lobits(MACADDR(a2)))
 		return 1;
 	else
+	{
+		if (size1 == 8 && size2 == 8)
+		{
+			if (lobits_extra(MACADDR(a1)) < lobits_extra(MACADDR(a2)))
+				return -1;
+			else if (lobits_extra(MACADDR(a1)) > lobits_extra(MACADDR(a2)))
+				return 1;
+		}
+		else if (size1 == 8)
+			return 1;
+		else if (size2 == 8)
+			return -1;
+
 		return 0;
+	}
 }
 
 Datum
 macaddr_cmp(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
 }
@@ -182,8 +281,8 @@ macaddr_cmp(PG_FUNCTION_ARGS)
 Datum
 macaddr_lt(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
 }
@@ -191,8 +290,8 @@ macaddr_lt(PG_FUNCTION_ARGS)
 Datum
 macaddr_le(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
 }
@@ -200,8 +299,8 @@ macaddr_le(PG_FUNCTION_ARGS)
 Datum
 macaddr_eq(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
 }
@@ -209,8 +308,8 @@ macaddr_eq(PG_FUNCTION_ARGS)
 Datum
 macaddr_ge(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
 }
@@ -218,8 +317,8 @@ macaddr_ge(PG_FUNCTION_ARGS)
 Datum
 macaddr_gt(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
 }
@@ -227,8 +326,8 @@ macaddr_gt(PG_FUNCTION_ARGS)
 Datum
 macaddr_ne(PG_FUNCTION_ARGS)
 {
-	macaddr    *a1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *a2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *a1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *a2 = PG_GETARG_MACADDR_PP(1);
 
 	PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
 }
@@ -239,9 +338,9 @@ macaddr_ne(PG_FUNCTION_ARGS)
 Datum
 hashmacaddr(PG_FUNCTION_ARGS)
 {
-	macaddr    *key = PG_GETARG_MACADDR_P(0);
+	macaddr    *key = PG_GETARG_MACADDR_PP(0);
 
-	return hash_any((unsigned char *) key, sizeof(macaddr));
+	return hash_any((unsigned char *) MACADDR(key), MACADDR_SIZE(key));
 }
 
 /*
@@ -250,50 +349,95 @@ hashmacaddr(PG_FUNCTION_ARGS)
 Datum
 macaddr_not(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr = PG_GETARG_MACADDR_P(0);
+	macaddr    *addr = PG_GETARG_MACADDR_PP(0);
 	macaddr    *result;
+	int 		size1 = MACADDR_SIZE(addr);
+	int 		size2 = MACADDR_SIZE(addr);
 
-	result = (macaddr *) palloc(sizeof(macaddr));
-	result->a = ~addr->a;
-	result->b = ~addr->b;
-	result->c = ~addr->c;
-	result->d = ~addr->d;
-	result->e = ~addr->e;
-	result->f = ~addr->f;
+	if (size1 != size2)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("Different length input addresses")));
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+	MACADDR(result)->data[0] = ~MACADDR(addr)->data[0];
+	MACADDR(result)->data[1] = ~MACADDR(addr)->data[1];
+	MACADDR(result)->data[2] = ~MACADDR(addr)->data[2];
+	MACADDR(result)->data[3] = ~MACADDR(addr)->data[3];
+	MACADDR(result)->data[4] = ~MACADDR(addr)->data[4];
+	MACADDR(result)->data[5] = ~MACADDR(addr)->data[5];
+
+	if (size1 == 8)
+	{
+		MACADDR(result)->data[6] = ~MACADDR(addr)->data[6];
+		MACADDR(result)->data[7] = ~MACADDR(addr)->data[7];
+	}
+
+	SET_MACADDR_VARSIZE(result, size1);
 	PG_RETURN_MACADDR_P(result);
 }
 
 Datum
 macaddr_and(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *addr1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *addr2 = PG_GETARG_MACADDR_PP(1);
 	macaddr    *result;
+	int 		size1 = MACADDR_SIZE(addr1);
+	int 		size2 = MACADDR_SIZE(addr1);
 
-	result = (macaddr *) palloc(sizeof(macaddr));
-	result->a = addr1->a & addr2->a;
-	result->b = addr1->b & addr2->b;
-	result->c = addr1->c & addr2->c;
-	result->d = addr1->d & addr2->d;
-	result->e = addr1->e & addr2->e;
-	result->f = addr1->f & addr2->f;
+	if (size1 != size2)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("Different length input addresses")));
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+	MACADDR(result)->data[0] = MACADDR(addr1)->data[0] & MACADDR(addr2)->data[0];
+	MACADDR(result)->data[1] = MACADDR(addr1)->data[1] & MACADDR(addr2)->data[1];
+	MACADDR(result)->data[2] = MACADDR(addr1)->data[2] & MACADDR(addr2)->data[2];
+	MACADDR(result)->data[3] = MACADDR(addr1)->data[3] & MACADDR(addr2)->data[3];
+	MACADDR(result)->data[4] = MACADDR(addr1)->data[4] & MACADDR(addr2)->data[4];
+	MACADDR(result)->data[5] = MACADDR(addr1)->data[5] & MACADDR(addr2)->data[5];
+
+	if (size1 == 8)
+	{
+		MACADDR(result)->data[6] = MACADDR(addr1)->data[6] & MACADDR(addr2)->data[6];
+		MACADDR(result)->data[7] = MACADDR(addr1)->data[7] & MACADDR(addr2)->data[7];
+	}
+
+	SET_MACADDR_VARSIZE(result, size1);
 	PG_RETURN_MACADDR_P(result);
 }
 
 Datum
 macaddr_or(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
-	macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
+	macaddr    *addr1 = PG_GETARG_MACADDR_PP(0);
+	macaddr    *addr2 = PG_GETARG_MACADDR_PP(1);
 	macaddr    *result;
+	int 		size1 = MACADDR_SIZE(addr1);
+	int 		size2 = MACADDR_SIZE(addr1);
 
-	result = (macaddr *) palloc(sizeof(macaddr));
-	result->a = addr1->a | addr2->a;
-	result->b = addr1->b | addr2->b;
-	result->c = addr1->c | addr2->c;
-	result->d = addr1->d | addr2->d;
-	result->e = addr1->e | addr2->e;
-	result->f = addr1->f | addr2->f;
+	if (size1 != size2)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("Different length input addresses")));
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+	MACADDR(result)->data[0] = MACADDR(addr1)->data[0] | MACADDR(addr2)->data[0];
+	MACADDR(result)->data[1] = MACADDR(addr1)->data[1] | MACADDR(addr2)->data[1];
+	MACADDR(result)->data[2] = MACADDR(addr1)->data[2] | MACADDR(addr2)->data[2];
+	MACADDR(result)->data[3] = MACADDR(addr1)->data[3] | MACADDR(addr2)->data[3];
+	MACADDR(result)->data[4] = MACADDR(addr1)->data[4] | MACADDR(addr2)->data[4];
+	MACADDR(result)->data[5] = MACADDR(addr1)->data[5] | MACADDR(addr2)->data[5];
+
+	if (size1 == 8)
+	{
+		MACADDR(result)->data[6] = MACADDR(addr1)->data[6] | MACADDR(addr2)->data[6];
+		MACADDR(result)->data[7] = MACADDR(addr1)->data[7] | MACADDR(addr2)->data[7];
+	}
+
+	SET_MACADDR_VARSIZE(result, size1);
 	PG_RETURN_MACADDR_P(result);
 }
 
@@ -304,17 +448,43 @@ macaddr_or(PG_FUNCTION_ARGS)
 Datum
 macaddr_trunc(PG_FUNCTION_ARGS)
 {
-	macaddr    *addr = PG_GETARG_MACADDR_P(0);
+	macaddr    *addr = PG_GETARG_MACADDR_PP(0);
 	macaddr    *result;
+	int 		size = MACADDR_SIZE(addr);
 
-	result = (macaddr *) palloc(sizeof(macaddr));
+	result = (macaddr *) palloc0(sizeof(macaddr));
 
-	result->a = addr->a;
-	result->b = addr->b;
-	result->c = addr->c;
-	result->d = 0;
-	result->e = 0;
-	result->f = 0;
+	MACADDR(result)->data[0] = MACADDR(addr)->data[0];
+	MACADDR(result)->data[1] = MACADDR(addr)->data[1];
+	MACADDR(result)->data[2] = MACADDR(addr)->data[2];
+	MACADDR(result)->data[3] = 0;
+	MACADDR(result)->data[4] = 0;
+	MACADDR(result)->data[5] = 0;
+	MACADDR(result)->data[6] = 0;
+	MACADDR(result)->data[7] = 0;
 
+	SET_MACADDR_VARSIZE(result, size);
 	PG_RETURN_MACADDR_P(result);
 }
+
+Datum
+mac6tomac(PG_FUNCTION_ARGS)
+{
+	macaddr6 *addr6 = PG_GETARG_MACADDR6_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	MACADDR(result)->data[0] = addr6->a;
+	MACADDR(result)->data[1] = addr6->b;
+	MACADDR(result)->data[2] = addr6->c;
+	MACADDR(result)->data[3] = 0xFF;
+	MACADDR(result)->data[4] = 0xFE;
+	MACADDR(result)->data[5] = addr6->d;
+	MACADDR(result)->data[6] = addr6->e;
+	MACADDR(result)->data[7] = addr6->f;
+
+	SET_MACADDR_VARSIZE(result, 8);
+	PG_RETURN_MACADDR_P(result);
+}
+
diff --git a/src/backend/utils/adt/mac6.c b/src/backend/utils/adt/mac6.c
new file mode 100644
index 0000000..670ca4b
--- /dev/null
+++ b/src/backend/utils/adt/mac6.c
@@ -0,0 +1,321 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
+ *
+ *	src/backend/utils/adt/mac.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+/*
+ *	MAC address reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr6_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr6    *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			  errmsg("invalid input syntax for type macaddr6: \"%s\"", str)));
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		   errmsg("invalid octet value in \"macaddr6\" value: \"%s\"", str)));
+
+	result = (macaddr6 *) palloc(sizeof(macaddr6));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+
+	PG_RETURN_MACADDR6_P(result);
+}
+
+/*
+ *	MAC address output function.  Fixed format.
+ */
+
+Datum
+macaddr6_out(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr = PG_GETARG_MACADDR6_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *		macaddr6_recv			- converts external binary format to macaddr6
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr6_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr6    *addr;
+
+	addr = (macaddr6 *) palloc(sizeof(macaddr6));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+	addr->d = pq_getmsgbyte(buf);
+	addr->e = pq_getmsgbyte(buf);
+	addr->f = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR6_P(addr);
+}
+
+/*
+ *		macaddr6_send			- converts macaddr6 to binary format
+ */
+Datum
+macaddr6_send(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr = PG_GETARG_MACADDR6_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr6_cmp_internal(macaddr6 *a1, macaddr6 *a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr6_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_INT32(macaddr6_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr6_lt(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr6_le(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr6_eq(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr6_ge(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr6_gt(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr6_ne(PG_FUNCTION_ARGS)
+{
+	macaddr6    *a1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *a2 = PG_GETARG_MACADDR6_P(1);
+
+	PG_RETURN_BOOL(macaddr6_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr6.
+ */
+Datum
+hashmacaddr6(PG_FUNCTION_ARGS)
+{
+	macaddr6    *key = PG_GETARG_MACADDR6_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr6));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr6_not(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *result;
+
+	result = (macaddr6 *) palloc(sizeof(macaddr6));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	PG_RETURN_MACADDR6_P(result);
+}
+
+Datum
+macaddr6_and(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *addr2 = PG_GETARG_MACADDR6_P(1);
+	macaddr6    *result;
+
+	result = (macaddr6 *) palloc(sizeof(macaddr6));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	PG_RETURN_MACADDR6_P(result);
+}
+
+Datum
+macaddr6_or(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr1 = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *addr2 = PG_GETARG_MACADDR6_P(1);
+	macaddr6    *result;
+
+	result = (macaddr6 *) palloc(sizeof(macaddr6));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	PG_RETURN_MACADDR6_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing mac manufacturers.
+ *	From suggestion by Alex Pilosov <alex@pilosoft.com>
+ */
+Datum
+macaddr6_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr6    *addr = PG_GETARG_MACADDR6_P(0);
+	macaddr6    *result;
+
+	result = (macaddr6 *) palloc(sizeof(macaddr6));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+
+	PG_RETURN_MACADDR6_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..bde433b 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -924,9 +924,9 @@ convert_network_to_scalar(Datum value, Oid typid)
 
 				break;
 			}
-		case MACADDROID:
+		case MACADDR6OID:
 			{
-				macaddr    *mac = DatumGetMacaddrP(value);
+				macaddr6    *mac = DatumGetMacaddr6P(value);
 				double		res;
 
 				res = (mac->a << 16) | (mac->b << 8) | (mac->c);
@@ -934,6 +934,24 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDROID:
+			{
+				macaddr    *mac = DatumGetMacaddrPP(value);
+				double		res;
+				int 		size = MACADDR_SIZE(mac);
+
+				res = (MACADDR(mac)->data[0] << 16) | (MACADDR(mac)->data[1] << 8) | (MACADDR(mac)->data[2]);
+				res *= 256 * 256 * 256;
+				res += (MACADDR(mac)->data[3] << 16) | (MACADDR(mac)->data[4] << 8) | (MACADDR(mac)->data[5]);
+
+				if (size == 8)
+				{
+					res *= 256 * 256;
+					res += (MACADDR(mac)->data[6] << 8) | (MACADDR(mac)->data[7]);
+				}
+
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 56943f2..46aa41e 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3783,6 +3783,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 			 */
 		case INETOID:
 		case CIDROID:
+		case MACADDR6OID:
 		case MACADDROID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index e4c3515..8b37dca 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -363,7 +363,7 @@ DATA(insert (	1982   1186 1186 4 s 1335 403 0 ));
 DATA(insert (	1982   1186 1186 5 s 1334 403 0 ));
 
 /*
- *	btree macaddr
+ *	btree macaddr6
  */
 
 DATA(insert (	1984   829 829 1 s 1222 403 0 ));
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -551,8 +561,10 @@ DATA(insert (	1977   20 21 1 s	1868 405 0 ));
 DATA(insert (	1977   20 23 1 s	416  405 0 ));
 /* interval_ops */
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
-/* macaddr_ops */
+/* macaddr6_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -993,12 +1005,18 @@ DATA(insert (	4073	703  703 2 s	   570	  3580 0 ));
 DATA(insert (	4073	703  703 3 s	   566	  3580 0 ));
 DATA(insert (	4073	703  703 4 s	   571	  3580 0 ));
 DATA(insert (	4073	703  703 5 s	   569	  3580 0 ));
-/* minmax macaddr */
+/* minmax macaddr6 */
 DATA(insert (	4074	829  829 1 s	  1222	  3580 0 ));
 DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr */
+DATA(insert (	5002	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	5002	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	5002	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	5002	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	5002	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f01a5b4..4bbe394 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 3358 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -409,11 +411,16 @@ DATA(insert (	4073   703	 703  1  3383 ));
 DATA(insert (	4073   703	 703  2  3384 ));
 DATA(insert (	4073   703	 703  3  3385 ));
 DATA(insert (	4073   703	 703  4  3386 ));
-/* minmax macaddr */
+/* minmax macaddr6 */
 DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr */
+DATA(insert (	5002   774	 774  1  3383 ));
+DATA(insert (	5002   774	 774  2  3384 ));
+DATA(insert (	5002   774	 774  3  3385 ));
+DATA(insert (	5002   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 04d11c0..74b4977 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,11 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    3373 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index ade8da3..a454a41 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -125,8 +125,10 @@ DATA(insert OID = 3124 ( 403	int8_ops	PGNSP PGUID 1976   20 t 0 ));
 DATA(insert (	405		int8_ops			PGNSP PGUID 1977   20 t 0 ));
 DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
-DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
-DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr6_ops		PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (	405		macaddr6_ops		PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr_ops			PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr_ops			PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -223,7 +225,8 @@ DATA(insert (	3580	float4_minmax_ops		PGNSP PGUID 4070   700 t 700 ));
 DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
-DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr6_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 5002   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 26fa618..f551079 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1113,25 +1113,46 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
+/* MAC6 type */
+DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr6_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr6_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 1222 (  "<"	   PGNSP PGUID b f f 829 829	 16 1224 1225 macaddr6_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 1223 (  "<="	   PGNSP PGUID b f f 829 829	 16 1225 1224 macaddr6_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 1224 (  ">"	   PGNSP PGUID b f f 829 829	 16 1222 1223 macaddr6_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 1225 (  ">="	   PGNSP PGUID b f f 829 829	 16 1223 1222 macaddr6_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3147 (  "~"	   PGNSP PGUID l f f	  0 829 829 0 0 macaddr6_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3148 (  "&"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr6_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr6_or - - ));
+DESCR("bitwise or");
+
 /* MAC type */
-DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
-DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr_ne neqsel neqjoinsel ));
 DESCR("not equal");
-DATA(insert OID = 1222 (  "<"	   PGNSP PGUID b f f 829 829	 16 1224 1225 macaddr_lt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr_lt scalarltsel scalarltjoinsel ));
 DESCR("less than");
-DATA(insert OID = 1223 (  "<="	   PGNSP PGUID b f f 829 829	 16 1225 1224 macaddr_le scalarltsel scalarltjoinsel ));
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr_le scalarltsel scalarltjoinsel ));
 DESCR("less than or equal");
-DATA(insert OID = 1224 (  ">"	   PGNSP PGUID b f f 829 829	 16 1222 1223 macaddr_gt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr_gt scalargtsel scalargtjoinsel ));
 DESCR("greater than");
-DATA(insert OID = 1225 (  ">="	   PGNSP PGUID b f f 829 829	 16 1223 1222 macaddr_ge scalargtsel scalargtjoinsel ));
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr_ge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
 
-DATA(insert OID = 3147 (  "~"	   PGNSP PGUID l f f	  0 829 829 0 0 macaddr_not - - ));
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr_not - - ));
 DESCR("bitwise not");
-DATA(insert OID = 3148 (  "&"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_and - - ));
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr_and - - ));
 DESCR("bitwise and");
-DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
 /* INET type (these also support CIDR via implicit cast) */
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 7ba23e5..bc7df09 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -85,8 +85,10 @@ DATA(insert OID = 1976 (	403		integer_ops		PGNSP PGUID ));
 DATA(insert OID = 1977 (	405		integer_ops		PGNSP PGUID ));
 DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
-DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
-DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 1984 (	403		macaddr6_ops	PGNSP PGUID ));
+DATA(insert OID = 1985 (	405		macaddr6_ops	PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -170,7 +172,8 @@ DATA(insert OID = 4069 (	3580	tid_minmax_ops			PGNSP PGUID ));
 DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
-DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4074 (	3580	macaddr6_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 5002 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 17ec71d..99e97f1 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -686,12 +686,14 @@ DATA(insert OID = 457 (  hashoidvector	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("hash");
 DATA(insert OID = 329 (  hash_aclitem	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1033" _null_ _null_ _null_ _null_ _null_	hash_aclitem _null_ _null_ _null_ ));
 DESCR("hash");
-DATA(insert OID = 399 (  hashmacaddr	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "829" _null_ _null_ _null_ _null_ _null_ hashmacaddr _null_ _null_ _null_ ));
+DATA(insert OID = 399 (  hashmacaddr6	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "829" _null_ _null_ _null_ _null_ _null_ hashmacaddr6 _null_ _null_ _null_ ));
 DESCR("hash");
 DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "869" _null_ _null_ _null_ _null_ _null_ hashinet _null_ _null_ _null_ ));
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2090,26 +2092,49 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
-DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
+/* for macaddr6 type support */
+DATA(insert OID = 436 (  macaddr6_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr6_in _null_ _null_ _null_ ));
 DESCR("I/O");
-DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
+DATA(insert OID = 437 (  macaddr6_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr6_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
-DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr6_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR6 manufacturer fields");
 
-DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
-DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
-DATA(insert OID = 832 (  macaddr_le			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_le _null_ _null_ _null_ ));
-DATA(insert OID = 833 (  macaddr_gt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_gt _null_ _null_ _null_ ));
-DATA(insert OID = 834 (  macaddr_ge			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_ge _null_ _null_ _null_ ));
-DATA(insert OID = 835 (  macaddr_ne			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_ne _null_ _null_ _null_ ));
-DATA(insert OID = 836 (  macaddr_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_cmp _null_ _null_ _null_ ));
+DATA(insert OID = 830 (  macaddr6_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_eq _null_ _null_ _null_ ));
+DATA(insert OID = 831 (  macaddr6_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_lt _null_ _null_ _null_ ));
+DATA(insert OID = 832 (  macaddr6_le			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_le _null_ _null_ _null_ ));
+DATA(insert OID = 833 (  macaddr6_gt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_gt _null_ _null_ _null_ ));
+DATA(insert OID = 834 (  macaddr6_ge			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_ge _null_ _null_ _null_ ));
+DATA(insert OID = 835 (  macaddr6_ne			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_ne _null_ _null_ _null_ ));
+DATA(insert OID = 836 (  macaddr6_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr6_cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
-DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_not _null_ _null_ _null_ ));
-DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
-DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
+DATA(insert OID = 3144 (  macaddr6_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr6_not _null_ _null_ _null_ ));
+DATA(insert OID = 3145 (  macaddr6_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr6_and _null_ _null_ _null_ ));
+DATA(insert OID = 3146 (  macaddr6_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr6_or _null_ _null_ _null_ ));
+
+/* for macaddr type support */
+DATA(insert OID = 3349 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3350 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 3351 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR manufacturer fields");
+
+DATA(insert OID = 3352 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3353 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
+DATA(insert OID = 3354 (  macaddr_le			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_le _null_ _null_ _null_ ));
+DATA(insert OID = 3355 (  macaddr_gt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_gt _null_ _null_ _null_ ));
+DATA(insert OID = 3356 (  macaddr_ge			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_ge _null_ _null_ _null_ ));
+DATA(insert OID = 3357 (  macaddr_ne			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_ne _null_ _null_ _null_ ));
+DATA(insert OID = 3358 (  macaddr_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 3359 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr_not _null_ _null_ _null_ ));
+DATA(insert OID = 3360 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
+DATA(insert OID = 3361 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
+DATA(insert OID = 3373 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ mac6tomac _null_ _null_ _null_ ));
+DESCR("convert macaddr6 to macaddr");
 
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
@@ -4016,9 +4041,9 @@ DATA(insert OID = 2492 (  cash_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 2493 (  cash_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "790" _null_ _null_ _null_ _null_ _null_ cash_send _null_ _null_ _null_ ));
 DESCR("I/O");
-DATA(insert OID = 2494 (  macaddr_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2281" _null_ _null_ _null_ _null_ _null_ macaddr_recv _null_ _null_ _null_ ));
+DATA(insert OID = 2494 (  macaddr6_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2281" _null_ _null_ _null_ _null_ _null_ macaddr6_recv _null_ _null_ _null_ ));
 DESCR("I/O");
-DATA(insert OID = 2495 (  macaddr_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "829" _null_ _null_ _null_ _null_ _null_ macaddr_send _null_ _null_ _null_ ));
+DATA(insert OID = 2495 (  macaddr6_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "829" _null_ _null_ _null_ _null_ _null_ macaddr6_send _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2496 (  inet_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2281" _null_ _null_ _null_ _null_ _null_ inet_recv _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4040,6 +4065,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr_recv	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr_send	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 162239c..5faadaa 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -432,18 +432,22 @@ DESCR("monetary amounts, $d,ddd.cc");
 DATA(insert OID = 791 (  _money    PGNSP PGUID	-1 f b A f t \054 0  790 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
 
 /* OIDS 800 - 899 */
-DATA(insert OID = 829 ( macaddr    PGNSP PGUID	6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 829 ( macaddr6    PGNSP PGUID	6 f b U f t \054 0 0 1040 macaddr6_in macaddr6_out macaddr6_recv macaddr6_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("XX:XX:XX:XX:XX:XX, MAC address");
-#define MACADDROID 829
+#define MACADDR6OID 829
 DATA(insert OID = 869 ( inet	   PGNSP PGUID	-1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("IP address/netmask, host address, netmask optional");
 #define INETOID 869
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr    PGNSP PGUID	-1 f b U f t \054 0 0 775 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDROID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -481,7 +485,8 @@ DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b U f t \054 0 0 1034 aclite
 DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
-DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 1040 (  _macaddr6	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 90f5132..39849c3 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1020,6 +1020,25 @@ extern Datum macaddr_and(PG_FUNCTION_ARGS);
 extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
+extern Datum mac6tomac(PG_FUNCTION_ARGS);
+
+/* mac6.c */
+extern Datum macaddr6_in(PG_FUNCTION_ARGS);
+extern Datum macaddr6_out(PG_FUNCTION_ARGS);
+extern Datum macaddr6_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr6_send(PG_FUNCTION_ARGS);
+extern Datum macaddr6_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr6_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr6_le(PG_FUNCTION_ARGS);
+extern Datum macaddr6_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr6_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr6_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr6_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr6_not(PG_FUNCTION_ARGS);
+extern Datum macaddr6_and(PG_FUNCTION_ARGS);
+extern Datum macaddr6_or(PG_FUNCTION_ARGS);
+extern Datum macaddr6_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr6(PG_FUNCTION_ARGS);
 
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 9fd954d..b203e51 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -91,7 +91,7 @@ typedef struct
 /*
  *	This is the internal storage format for MAC addresses:
  */
-typedef struct macaddr
+typedef struct macaddr6
 {
 	unsigned char a;
 	unsigned char b;
@@ -99,6 +99,20 @@ typedef struct macaddr
 	unsigned char d;
 	unsigned char e;
 	unsigned char f;
+} macaddr6;
+
+typedef struct mac_struct
+{
+	unsigned char data[8]; /* Max storage of 8 byte MAC address */
+}mac_struct;
+
+/*
+ *	This is the internal storage format for MAC addresses (EUI-48 & EUI-64):
+ */
+typedef struct macaddr
+{
+	char		vl_len_[4];		/* Do not touch this field directly! */
+	mac_struct 	addr;
 } macaddr;
 
 /*
@@ -110,12 +124,26 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
-/* macaddr is a fixed-length pass-by-reference datatype */
-#define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
+
+/* macaddr6 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr6P(X)    ((macaddr6 *) DatumGetPointer(X))
+#define Macaddr6PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR6_P(n) DatumGetMacaddr6P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR6_P(x) return Macaddr6PGetDatum(x)
+
+/* macaddr is a variable length datatype */
+#define DatumGetMacaddrP(X)    ((macaddr *) PG_DETOAST_DATUM(X))
+#define DatumGetMacaddrPP(X)	((macaddr *) PG_DETOAST_DATUM_PACKED(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
+#define PG_GETARG_MACADDR_PP(n) DatumGetMacaddrPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr supported macros  */
+#define SET_MACADDR_VARSIZE(dst, size) SET_VARSIZE((dst), VARHDRSZ + (size))
+#define MACADDR(ptr) ((mac_struct *)VARDATA_ANY(ptr))
+#define MACADDR_SIZE(ptr) (VARSIZE_ANY_EXHDR(ptr))
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr.out b/src/test/regress/expected/macaddr.out
index e84ff5f..63ad959 100644
--- a/src/test/regress/expected/macaddr.out
+++ b/src/test/regress/expected/macaddr.out
@@ -22,9 +22,15 @@ INSERT INTO macaddr_data VALUES (11, '08:00:2b:01:02:02');
 INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03');
 INSERT INTO macaddr_data VALUES (13, '08:00:2c:01:02:03');
 INSERT INTO macaddr_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr_data VALUES (20, '08002b0102030405');
 SELECT * FROM macaddr_data;
- a  |         b         
-----+-------------------
+ a  |            b            
+----+-------------------------
   1 | 08:00:2b:01:02:03
   2 | 08:00:2b:01:02:03
   3 | 08:00:2b:01:02:03
@@ -37,27 +43,39 @@ SELECT * FROM macaddr_data;
  12 | 08:00:2a:01:02:03
  13 | 08:00:2c:01:02:03
  14 | 08:00:2a:01:02:04
-(12 rows)
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+(18 rows)
 
 CREATE INDEX macaddr_data_btree ON macaddr_data USING btree (b);
 CREATE INDEX macaddr_data_hash ON macaddr_data USING hash (b);
 WARNING:  hash indexes are not WAL-logged and their use is discouraged
 SELECT a, b, trunc(b) FROM macaddr_data ORDER BY 2, 1;
- a  |         b         |       trunc       
-----+-------------------+-------------------
- 12 | 08:00:2a:01:02:03 | 08:00:2a:00:00:00
- 14 | 08:00:2a:01:02:04 | 08:00:2a:00:00:00
- 11 | 08:00:2b:01:02:02 | 08:00:2b:00:00:00
-  1 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  2 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  3 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  4 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  5 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  6 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
-  7 | 08:00:2b:01:02:03 | 08:00:2b:00:00:00
- 10 | 08:00:2b:01:02:04 | 08:00:2b:00:00:00
- 13 | 08:00:2c:01:02:03 | 08:00:2c:00:00:00
-(12 rows)
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:01:02:03       | 08:00:2a:00:00:00
+ 14 | 08:00:2a:01:02:04       | 08:00:2a:00:00:00
+ 11 | 08:00:2b:01:02:02       | 08:00:2b:00:00:00
+  1 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  2 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  3 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  4 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  5 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  6 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+  7 | 08:00:2b:01:02:03       | 08:00:2b:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:01:02:04       | 08:00:2b:00:00:00
+ 13 | 08:00:2c:01:02:03       | 08:00:2c:00:00:00
+(18 rows)
 
 SELECT b <  '08:00:2b:01:02:04' FROM macaddr_data WHERE a = 1; -- true
  ?column? 
@@ -107,9 +125,57 @@ SELECT b <> '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- false
  f
 (1 row)
 
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
 SELECT ~b                       FROM macaddr_data;
-     ?column?      
--------------------
+        ?column?         
+-------------------------
  f7:ff:d4:fe:fd:fc
  f7:ff:d4:fe:fd:fc
  f7:ff:d4:fe:fd:fc
@@ -122,11 +188,17 @@ SELECT ~b                       FROM macaddr_data;
  f7:ff:d5:fe:fd:fc
  f7:ff:d3:fe:fd:fc
  f7:ff:d5:fe:fd:fb
-(12 rows)
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(18 rows)
 
 SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
-     ?column?      
--------------------
+        ?column?         
+-------------------------
  00:00:00:01:02:03
  00:00:00:01:02:03
  00:00:00:01:02:03
@@ -139,11 +211,17 @@ SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
  00:00:00:01:02:03
  00:00:00:01:02:03
  00:00:00:01:02:04
-(12 rows)
+ 00:00:00:01:02:03:00:00
+ 00:00:00:01:02:03:00:00
+ 00:00:00:01:02:03:00:00
+ 00:00:00:01:02:03:00:00
+ 00:00:00:01:02:03:00:00
+ 00:00:00:01:02:03:00:00
+(18 rows)
 
 SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
-     ?column?      
--------------------
+        ?column?         
+-------------------------
  09:02:2b:05:07:07
  09:02:2b:05:07:07
  09:02:2b:05:07:07
@@ -156,6 +234,12 @@ SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
  09:02:2b:05:07:07
  09:02:2f:05:07:07
  09:02:2b:05:07:06
-(12 rows)
+ 09:02:2b:05:07:07:04:05
+ 09:02:2b:05:07:07:04:05
+ 09:02:2b:05:07:07:04:05
+ 09:02:2b:05:07:07:04:05
+ 09:02:2b:05:07:07:04:05
+ 09:02:2b:05:07:07:04:05
+(18 rows)
 
 DROP TABLE macaddr_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..16e79a8 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -561,12 +561,12 @@ tintervallt(tinterval,tinterval)
 tintervalgt(tinterval,tinterval)
 tintervalle(tinterval,tinterval)
 tintervalge(tinterval,tinterval)
-macaddr_eq(macaddr,macaddr)
-macaddr_lt(macaddr,macaddr)
-macaddr_le(macaddr,macaddr)
-macaddr_gt(macaddr,macaddr)
-macaddr_ge(macaddr,macaddr)
-macaddr_ne(macaddr,macaddr)
+macaddr6_eq(macaddr6,macaddr6)
+macaddr6_lt(macaddr6,macaddr6)
+macaddr6_le(macaddr6,macaddr6)
+macaddr6_gt(macaddr6,macaddr6)
+macaddr6_ge(macaddr6,macaddr6)
+macaddr6_ne(macaddr6,macaddr6)
 int48eq(integer,bigint)
 int48ne(integer,bigint)
 int48lt(integer,bigint)
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr_eq(macaddr,macaddr)
+macaddr_lt(macaddr,macaddr)
+macaddr_le(macaddr,macaddr)
+macaddr_gt(macaddr,macaddr)
+macaddr_ge(macaddr,macaddr)
+macaddr_ne(macaddr,macaddr)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/sql/macaddr.sql b/src/test/regress/sql/macaddr.sql
index 7bad8f5..173c978 100644
--- a/src/test/regress/sql/macaddr.sql
+++ b/src/test/regress/sql/macaddr.sql
@@ -20,6 +20,14 @@ INSERT INTO macaddr_data VALUES (12, '08:00:2a:01:02:03');
 INSERT INTO macaddr_data VALUES (13, '08:00:2c:01:02:03');
 INSERT INTO macaddr_data VALUES (14, '08:00:2a:01:02:04');
 
+INSERT INTO macaddr_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr_data VALUES (20, '08002b0102030405');
+
+
 SELECT * FROM macaddr_data;
 
 CREATE INDEX macaddr_data_btree ON macaddr_data USING btree (b);
@@ -36,6 +44,15 @@ SELECT b =  '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- true
 SELECT b <> '08:00:2b:01:02:04' FROM macaddr_data WHERE a = 1; -- true
 SELECT b <> '08:00:2b:01:02:03' FROM macaddr_data WHERE a = 1; -- false
 
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr_data WHERE a = 15; -- false
+
 SELECT ~b                       FROM macaddr_data;
 SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr_data;
 SELECT  b | '01:02:03:04:05:06' FROM macaddr_data;
#25Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Haribabu Kommi (#24)
Re: macaddr 64 bit (EUI-64) datatype support

On 10/25/16 1:38 AM, Haribabu Kommi wrote:

Here I attached the first version of patch that supports both EUI-48 and
EUI-64 type
Mac addresses with a single datatype called macaddr. This is an variable
length
datatype similar like inet. It can store both 6 and 8 byte addresses.
Variable length
type is used because in case in future, if MAC address gets enhanced,
still this type
can support without breaking DISK compatibility.

Since the world knows the 6-byte variant as MAC-48, shouldn't it be
renamed to macaddr48 or even mac48?

Currently the patch lacks of documentation. Comments?

For patches like this, it would be good if you included a mock commit
message so that someone who comes in late knows what's going on.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#26Robert Haas
robertmhaas@gmail.com
In reply to: Bruce Momjian (#23)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Oct 18, 2016 at 7:25 PM, Bruce Momjian <bruce@momjian.us> wrote:

On Wed, Oct 12, 2016 at 08:33:00AM -0400, Tom Lane wrote:

As others have noted, there is no likelihood that we'd take a disk-format-
compatibility-breaking patch for v10. Even if we wanted to do that, the
above proposal would also break send/recv (binary COPY) compatibility for
macaddr.

I think that probably the best bet here is to have two types and put some
thought into making them interoperate where appropriate, as the various
sizes of int do. It's kind of a shame that this won't look like the
approach used for inet addresses, but we're stuck.

If feels like we are going into VARCHAR2 territory where we end up
telling people to use an oddly-named data type forever. Some are
suggesting JSONB is in that category.

I think that's just the price of maintaining a stable database system
over the course of many years. You end up with a few warts in the
name of backward compatibility. It's not wonderful to have warts, but
backward compatibility has enough value to make it worth enduring the
warts. If the worst thing that happens is we end up with types called
jsonb and macaddr8, we're doing well. Obviously, there's some point
at which maintaining backward compatibility becomes too much of a
nuisance to be worthwhile, and that's why we've periodically made
compatibility breaks of various types. I'm sure we'll continue to do
that in the future from time to time, but I wouldn't do it here. I
think Tom's got the right idea: let's leave the existing datatype
alone to avoid breaking things for people who are already using it,
and add a new one for people to enable the new functionality.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Peter Eisentraut (#25)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Oct 25, 2016 at 11:40 PM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

On 10/25/16 1:38 AM, Haribabu Kommi wrote:

Here I attached the first version of patch that supports both EUI-48 and
EUI-64 type
Mac addresses with a single datatype called macaddr. This is an variable
length
datatype similar like inet. It can store both 6 and 8 byte addresses.
Variable length
type is used because in case in future, if MAC address gets enhanced,
still this type
can support without breaking DISK compatibility.

Since the world knows the 6-byte variant as MAC-48, shouldn't it be
renamed to macaddr48 or even mac48?

Yes. Before doing this change, it is better to confirm the approach and
then do all the changes.

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

2. The old macaddress datatype rename to mac48 macaddr48
or macaddr6 or mac6.

3. Add the new datatype with the name that supports both 48 bit
and 64 bit MAC address.

4. The new datatype is of variable length datatype similar like INET,
so it can handle any future changes.

Currently the patch lacks of documentation. Comments?

For patches like this, it would be good if you included a mock commit
message so that someone who comes in late knows what's going on.

Thanks, I will do it from now onward.

Regards,
Hari Babu
Fujitsu Australia

#28Shay Rojansky
roji@roji.org
In reply to: Haribabu Kommi (#27)
Re: macaddr 64 bit (EUI-64) datatype support

Yes. Before doing this change, it is better to confirm the approach and
then do all the changes.

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

As I said before, Npgsql for one loads data types by name, not by OID. So
this would definitely cause breakage.

For users who actually need the new variable-length type, it seems
perfectly reasonable to ask to switch to a new type - after all they're
making a change in their system. It would really be preferable to leave the
current type alone and create a new one.

#29Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Shay Rojansky (#28)
Re: macaddr 64 bit (EUI-64) datatype support

On 11/4/16 4:55 AM, Shay Rojansky wrote:

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

As I said before, Npgsql for one loads data types by name, not by OID.
So this would definitely cause breakage.

Why would that cause breakage?

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Shay Rojansky
roji@roji.org
In reply to: Peter Eisentraut (#29)
Re: macaddr 64 bit (EUI-64) datatype support

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

As I said before, Npgsql for one loads data types by name, not by OID.
So this would definitely cause breakage.

Why would that cause breakage?

Well, the first thing Npgsql does when it connects to a new database, is to
query pg_type. The type names are used to associate entries with type
handlers, avoiding the hard-coding of OIDs in code. So if the type name
"macaddr" suddenly has a new meaning and its wire representation is
different breakage will occur. It is possible to release new versions of
Npgsql which will look at the PostgreSQL version and say "we know that in
PostgreSQL < 10 macaddr means this, but in >= 10 it means that". But that
doesn't seem like a good solution, plus old versions of Npgsql from before
this change won't work.

#31Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Shay Rojansky (#30)
Re: macaddr 64 bit (EUI-64) datatype support

On Mon, Nov 7, 2016 at 8:40 AM, Shay Rojansky <roji@roji.org> wrote:

1. Does everyone agrees that renaming the existing datatype without

changing the OID?

As I said before, Npgsql for one loads data types by name, not by OID.
So this would definitely cause breakage.

Why would that cause breakage?

Well, the first thing Npgsql does when it connects to a new database, is
to query pg_type. The type names are used to associate entries with type
handlers, avoiding the hard-coding of OIDs in code. So if the type name
"macaddr" suddenly has a new meaning and its wire representation is
different breakage will occur. It is possible to release new versions of
Npgsql which will look at the PostgreSQL version and say "we know that in
PostgreSQL < 10 macaddr means this, but in >= 10 it means that". But that
doesn't seem like a good solution, plus old versions of Npgsql from before
this change won't work.

The new datatype that is going to replace the existing one works with both
6 and 8 byte
MAC address and stores it a variable length format. This doesn't change the
wire format.
I don't see any problem with the existing applications. The new datatype
can recv and send
8 byte MAC address also.

Regards,
Hari Babu
Fujitsu Australia

#32Shay Rojansky
roji@roji.org
In reply to: Haribabu Kommi (#31)
Re: macaddr 64 bit (EUI-64) datatype support

As I said before, Npgsql for one loads data types by name, not by OID.

So this would definitely cause breakage.

Why would that cause breakage?

Well, the first thing Npgsql does when it connects to a new database, is
to query pg_type. The type names are used to associate entries with type
handlers, avoiding the hard-coding of OIDs in code. So if the type name
"macaddr" suddenly has a new meaning and its wire representation is
different breakage will occur. It is possible to release new versions of
Npgsql which will look at the PostgreSQL version and say "we know that in
PostgreSQL < 10 macaddr means this, but in >= 10 it means that". But that
doesn't seem like a good solution, plus old versions of Npgsql from before
this change won't work.

The new datatype that is going to replace the existing one works with both
6 and 8 byte
MAC address and stores it a variable length format. This doesn't change
the wire format.
I don't see any problem with the existing applications. The new datatype
can recv and send
8 byte MAC address also.

Apologies, I may have misunderstood. If the new type is 100%
wire-compatible (recv/send) with the old fixed-length 6-byte type, then
there's no issue whatsoever.

#33Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Haribabu Kommi (#27)
Re: macaddr 64 bit (EUI-64) datatype support

On Fri, Nov 4, 2016 at 11:09 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

On Tue, Oct 25, 2016 at 11:40 PM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

On 10/25/16 1:38 AM, Haribabu Kommi wrote:

Here I attached the first version of patch that supports both EUI-48 and
EUI-64 type
Mac addresses with a single datatype called macaddr. This is an variable
length
datatype similar like inet. It can store both 6 and 8 byte addresses.
Variable length
type is used because in case in future, if MAC address gets enhanced,
still this type
can support without breaking DISK compatibility.

Since the world knows the 6-byte variant as MAC-48, shouldn't it be
renamed to macaddr48 or even mac48?

Yes. Before doing this change, it is better to confirm the approach and
then do all the changes.

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

2. The old macaddress datatype rename to mac48 macaddr48
or macaddr6 or mac6.

3. Add the new datatype with the name that supports both 48 bit
and 64 bit MAC address.

4. The new datatype is of variable length datatype similar like INET,
so it can handle any future changes.

I didn't hear any problems with the approach in supporting the MACADDR
with 8 bytes storage. I will go with proposed design, and "mac48" as
the datatype name for the old macaddr.

Regards,
Hari Babu
Fujitsu Australia

On Fri, Nov 4, 2016 at 11:09 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

On Tue, Oct 25, 2016 at 11:40 PM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

On 10/25/16 1:38 AM, Haribabu Kommi wrote:

Here I attached the first version of patch that supports both EUI-48 and
EUI-64 type
Mac addresses with a single datatype called macaddr. This is an variable
length
datatype similar like inet. It can store both 6 and 8 byte addresses.
Variable length
type is used because in case in future, if MAC address gets enhanced,
still this type
can support without breaking DISK compatibility.

Since the world knows the 6-byte variant as MAC-48, shouldn't it be
renamed to macaddr48 or even mac48?

Yes. Before doing this change, it is better to confirm the approach and
then do all the changes.

1. Does everyone agrees that renaming the existing datatype without
changing the OID?

2. The old macaddress datatype rename to mac48 macaddr48
or macaddr6 or mac6.

3. Add the new datatype with the name that supports both 48 bit
and 64 bit MAC address.

4. The new datatype is of variable length datatype similar like INET,
so it can handle any future changes.

Currently the patch lacks of documentation. Comments?

For patches like this, it would be good if you included a mock commit
message so that someone who comes in late knows what's going on.

Thanks, I will do it from now onward.

Regards,
Hari Babu
Fujitsu Australia

--
Regards,
Hari Babu
Fujitsu Australia

#34Stephen Frost
sfrost@snowman.net
In reply to: Shay Rojansky (#32)
Re: macaddr 64 bit (EUI-64) datatype support

* Shay Rojansky (roji@roji.org) wrote:

As I said before, Npgsql for one loads data types by name, not by OID.

So this would definitely cause breakage.

Why would that cause breakage?

Well, the first thing Npgsql does when it connects to a new database, is
to query pg_type. The type names are used to associate entries with type
handlers, avoiding the hard-coding of OIDs in code. So if the type name
"macaddr" suddenly has a new meaning and its wire representation is
different breakage will occur. It is possible to release new versions of
Npgsql which will look at the PostgreSQL version and say "we know that in
PostgreSQL < 10 macaddr means this, but in >= 10 it means that". But that
doesn't seem like a good solution, plus old versions of Npgsql from before
this change won't work.

The new datatype that is going to replace the existing one works with both
6 and 8 byte
MAC address and stores it a variable length format. This doesn't change
the wire format.
I don't see any problem with the existing applications. The new datatype
can recv and send
8 byte MAC address also.

Apologies, I may have misunderstood. If the new type is 100%
wire-compatible (recv/send) with the old fixed-length 6-byte type, then
there's no issue whatsoever.

Uh, that certainly isn't correct, is it...?

The new data type is going to be able to send back 8-byte values to a
Npgsql driver that's not expecting to get back 8 byte macaddrs. That
isn't going to work.

Further, I don't agree that we can simply rename the existing macaddr to
something else, even if we keep the same OID, that's going to confuse
the heck out of people who are doing pg_upgrade's 9.6 to 10 and then
they try to do migrations using their previous systems or even to
compare the output of pg_dump from one to the next.

Let's create a new data type for this which supports old and new types,
add what casts make sense, and call it a day. Changing the data type
name out from under people is not helping anyone.

Thanks!

Stephen

#35Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#34)
Re: macaddr 64 bit (EUI-64) datatype support

Stephen Frost <sfrost@snowman.net> writes:

Let's create a new data type for this which supports old and new types,
add what casts make sense, and call it a day. Changing the data type
name out from under people is not helping anyone.

+1. I do not think changing behavior for the existing type name is
going to be a net win. If we'd been smart enough to make the type
varlena from the get-go, maybe we could get away with it, but there
is just way too much risk of trouble with a change in a fixed-length
type's on-the-wire representation.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#36Robert Haas
robertmhaas@gmail.com
In reply to: Tom Lane (#35)
Re: macaddr 64 bit (EUI-64) datatype support

On Sat, Nov 19, 2016 at 2:54 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Stephen Frost <sfrost@snowman.net> writes:

Let's create a new data type for this which supports old and new types,
add what casts make sense, and call it a day. Changing the data type
name out from under people is not helping anyone.

+1. I do not think changing behavior for the existing type name is
going to be a net win. If we'd been smart enough to make the type
varlena from the get-go, maybe we could get away with it, but there
is just way too much risk of trouble with a change in a fixed-length
type's on-the-wire representation.

I completely agree.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Robert Haas (#36)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Nov 22, 2016 at 5:33 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Sat, Nov 19, 2016 at 2:54 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Stephen Frost <sfrost@snowman.net> writes:

Let's create a new data type for this which supports old and new types,
add what casts make sense, and call it a day. Changing the data type
name out from under people is not helping anyone.

+1. I do not think changing behavior for the existing type name is
going to be a net win. If we'd been smart enough to make the type
varlena from the get-go, maybe we could get away with it, but there
is just way too much risk of trouble with a change in a fixed-length
type's on-the-wire representation.

I completely agree.

OK. Agreed.

Any suggestions for the name to be used for the new datatype the can
work for both 48 and 64 bit MAC addresses?

It is possible to represent a 48 bit MAC address as 64 bit MAC address
by adding reserved bytes in the middle as follows.

01-01-01-01-01-01::macaddr => 01-01-01-FF-FE-01-01-01::newmacaddr

While comparing a 48 bit MAC address with 64 bit MAC address, Ignore
the two bytes if the contents in those bytes are reserved bytes.

The new datatype can store directly whatever is the input is, like 48 bit
or 64 bit. The same data is sent over the wire, whether the reserved
bytes are present or not?

Regards,
Hari Babu
Fujitsu Australia

#38Tom Lane
tgl@sss.pgh.pa.us
In reply to: Haribabu Kommi (#37)
Re: macaddr 64 bit (EUI-64) datatype support

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Any suggestions for the name to be used for the new datatype the can
work for both 48 and 64 bit MAC addresses?

The precedent of int4/int8/float4/float8 is that SQL data types should
be named after their length in bytes. So I'd be inclined to call this
"macaddr8" not "macaddr64". That would suggest taking the simple
approach of always storing values in the 8-byte format, rather than
dealing with the complexities of having two formats internally, two
display formats, etc.

It is possible to represent a 48 bit MAC address as 64 bit MAC address
by adding reserved bytes in the middle as follows.
01-01-01-01-01-01::macaddr => 01-01-01-FF-FE-01-01-01::newmacaddr

Check. So we could accept 6-byte addresses on input and perform
that conversion automatically.

While comparing a 48 bit MAC address with 64 bit MAC address, Ignore
the two bytes if the contents in those bytes are reserved bytes.

Um ... I don't follow. Surely these must compare different:

01-01-01-FF-FE-01-01-01
01-01-01-FF-0E-01-01-01

The new datatype can store directly whatever is the input is, like 48 bit
or 64 bit. The same data is sent over the wire, whether the reserved
bytes are present or not?

I'd just send all 8 bytes. What the client wants to do with values
that could be mapped back into the 6-byte space is its business.

In short, let's just make this work similarly to integers of different
widths, rather than trying to sprinkle extra pixie dust on it.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Jon Nelson
jnelson+pgsql@jamponi.net
In reply to: Tom Lane (#38)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Nov 22, 2016 at 8:42 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Any suggestions for the name to be used for the new datatype the can
work for both 48 and 64 bit MAC addresses?

The precedent of int4/int8/float4/float8 is that SQL data types should
be named after their length in bytes. So I'd be inclined to call this
"macaddr8" not "macaddr64". That would suggest taking the simple
approach of always storing values in the 8-byte format, rather than
dealing with the complexities of having two formats internally, two
display formats, etc.

Be that as it may, but almost everybody else (outside the db world?) uses
bits. The C types, for example, are expressed in bits (int8_t, int64_t,
etc...).

While comparing a 48 bit MAC address with 64 bit MAC address, Ignore

the two bytes if the contents in those bytes are reserved bytes.

Um ... I don't follow. Surely these must compare different:

01-01-01-FF-FE-01-01-01
01-01-01-FF-0E-01-01-01

What's more, it now requires 2 comparisons and some logic versus the
possibility of a single memcmp.

--
Jon

#40Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Tom Lane (#38)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Nov 23, 2016 at 1:42 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Any suggestions for the name to be used for the new datatype the can
work for both 48 and 64 bit MAC addresses?

The precedent of int4/int8/float4/float8 is that SQL data types should
be named after their length in bytes. So I'd be inclined to call this
"macaddr8" not "macaddr64". That would suggest taking the simple
approach of always storing values in the 8-byte format, rather than
dealing with the complexities of having two formats internally, two
display formats, etc.

It is possible to represent a 48 bit MAC address as 64 bit MAC address
by adding reserved bytes in the middle as follows.
01-01-01-01-01-01::macaddr => 01-01-01-FF-FE-01-01-01::newmacaddr

Check. So we could accept 6-byte addresses on input and perform
that conversion automatically.

Do you prefer the automatic conversion from 6 byte to 8 byte MAC address,
This way it takes extra space with new datatype. Is it fine to with new
datatype?

While comparing a 48 bit MAC address with 64 bit MAC address, Ignore
the two bytes if the contents in those bytes are reserved bytes.

Um ... I don't follow. Surely these must compare different:

01-01-01-FF-FE-01-01-01
01-01-01-FF-0E-01-01-01

Yes, that's correct. Both the above MAC addresses are different.

Sorry for not providing more details.

The new macaddr8 datatype can accept both 6 and 8 byte MAC addresses.
Let's assume the data in the table for the macaddr8 column as follows.

row1 = 01-01-01-02-02-02
row2 = 01-01-01-FF-FE-02-02-02

The MAC address is same, it is just a representation in 2 forms, one is 6
byte
and another is 8 byte.

What I am suggesting is, we can treat both of the rows data as same, because
it is just a representation difference.

To do the same, while comparing two MAC addresses that are of 6 and 8 byte
length, some special handling is added to check for the reserved keywords
in
the 8 byte MAC address, based on that the comparison is carried out.

The new datatype can store directly whatever is the input is, like 48 bit

or 64 bit. The same data is sent over the wire, whether the reserved
bytes are present or not?

I'd just send all 8 bytes. What the client wants to do with values
that could be mapped back into the 6-byte space is its business.

As the new datatype that can store both 6 and 8 byte MAC addresses
as it is, while sending this data to client, based on the data that is
stored,
it sends 6 or 8 bytes.

If we go with storing 8 byte always, then sending all 8 bytes is fine.

Regards,
Hari Babu
Fujitsu Australia

#41Tom Lane
tgl@sss.pgh.pa.us
In reply to: Haribabu Kommi (#40)
Re: macaddr 64 bit (EUI-64) datatype support

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

On Wed, Nov 23, 2016 at 1:42 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

The precedent of int4/int8/float4/float8 is that SQL data types should
be named after their length in bytes. So I'd be inclined to call this
"macaddr8" not "macaddr64". That would suggest taking the simple
approach of always storing values in the 8-byte format, rather than
dealing with the complexities of having two formats internally, two
display formats, etc.

Do you prefer the automatic conversion from 6 byte to 8 byte MAC address,
This way it takes extra space with new datatype. Is it fine to with new
datatype?

Well, I think the space savings would be pretty illusory. If we use a
varlena datatype, then old-style MAC addresses would take 7 bytes and
new-style would take 9. That's not much of an improvement over always
taking 8 bytes. What's worse, if the next field has an alignment
requirement more than char, is that it's really 8 bytes and 12 bytes (or
16!), making this strictly worse than a fixed-length-8-bytes approach.

As against that, if we use a varlena type then we'd have some protection
against the day when the MAC people realize they were still being
short-sighted and go up to 10 or 12 or 16 bytes. But even if that happens
while Postgres is still in use, I'm not sure that we'd choose to make use
of the varlena aspect rather than invent a third datatype to go with that
new version of the standard. Per the discussion in this thread, varlena
storage in itself doesn't do very much for the client-side compatibility
issues. Making a new datatype with a new, well-defined I/O behavior
ensures that applications don't get blindsided by a new behavior they're
not ready for.

In short, I'm leaning to having just a fixed-length-8-byte implementation.
This may seem like learning nothing from our last go-round, but the
advantages of varlena are very far in the hypothetical future, and the
disadvantages are immediate.

Also, if we define macaddr as "always 6 bytes" and macaddr8 as "always 8
bytes", then there's a very simple way for users to widen an old-style
address to 8 bytes or convert it back to the 6-byte format: just cast
to the other datatype. If the new macaddr type can store both widths
then you need to invent at least one additional function to provide
those behaviors.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#42Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Tom Lane (#41)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Nov 23, 2016 at 12:53 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

On Wed, Nov 23, 2016 at 1:42 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

The precedent of int4/int8/float4/float8 is that SQL data types should
be named after their length in bytes. So I'd be inclined to call this
"macaddr8" not "macaddr64". That would suggest taking the simple
approach of always storing values in the 8-byte format, rather than
dealing with the complexities of having two formats internally, two
display formats, etc.

Do you prefer the automatic conversion from 6 byte to 8 byte MAC address,
This way it takes extra space with new datatype. Is it fine to with new
datatype?

Well, I think the space savings would be pretty illusory. If we use a
varlena datatype, then old-style MAC addresses would take 7 bytes and
new-style would take 9. That's not much of an improvement over always
taking 8 bytes. What's worse, if the next field has an alignment
requirement more than char, is that it's really 8 bytes and 12 bytes (or
16!), making this strictly worse than a fixed-length-8-bytes approach.

As against that, if we use a varlena type then we'd have some protection
against the day when the MAC people realize they were still being
short-sighted and go up to 10 or 12 or 16 bytes. But even if that happens
while Postgres is still in use, I'm not sure that we'd choose to make use
of the varlena aspect rather than invent a third datatype to go with that
new version of the standard. Per the discussion in this thread, varlena
storage in itself doesn't do very much for the client-side compatibility
issues. Making a new datatype with a new, well-defined I/O behavior
ensures that applications don't get blindsided by a new behavior they're
not ready for.

In short, I'm leaning to having just a fixed-length-8-byte implementation.
This may seem like learning nothing from our last go-round, but the
advantages of varlena are very far in the hypothetical future, and the
disadvantages are immediate.

Also, if we define macaddr as "always 6 bytes" and macaddr8 as "always 8
bytes", then there's a very simple way for users to widen an old-style
address to 8 bytes or convert it back to the 6-byte format: just cast
to the other datatype. If the new macaddr type can store both widths
then you need to invent at least one additional function to provide
those behaviors.

Thanks for your feedback.

Here is attached updated patch with new datatype "macaddr8" with fixed
length
of 8 bytes.

If your input a 6 byte MAC address, it automatically converts it into an 8
byte
MAC address by adding the reserved keywords and store it as an 8 byte
address.

While sending it to client it always send an 8 byte MAC address.

Currently the casting is supported from macaddr to macaddr8, but not the
other way. This is because, not all 8 byte MAC addresses can be converted
into
6 byte addresses.

Test and doc changes are also added.

comments?

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_2.patchapplication/octet-stream; name=mac_eui64_support_2.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index e8a5622..479b751 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 67d0c34..8d29e52 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -165,6 +165,12 @@
        <entry></entry>
        <entry>MAC (Media Access Control) address</entry>
       </row>
+      
+      <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
 
       <row>
        <entry><type>money</type></entry>
@@ -3459,6 +3465,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>6 bytes</entry>
         <entry>MAC addresses</entry>
        </row>
+       
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
 
       </tbody>
      </tgroup>
@@ -3700,6 +3712,52 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses.
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+    
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+
+    <para>
+     The remaining six input formats are not part of any standard.
+    </para>
+   </sect2>
+   
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2e64cc4..eed1695 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9224,6 +9224,51 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 3 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 3 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    lexicographical ordering, and the bitwise arithmetic operators
+    (<literal>~</literal>, <literal>&amp;</literal> and <literal>|</literal>)
+    for NOT, AND and OR.
+   </para>
+   
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 509315a..ef0810e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..968429e
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,446 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *  The following code is written with the assumption of
+ *  OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->g<<8)|((addr)->h))
+
+/*
+ *	MAC address (EUI-48 and EUI-64) reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8    *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g = 0,
+				h = 0;
+	char		junk[2];
+	int			count;
+	bool 		eight_byte_address = false;
+
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		eight_byte_address = true;
+
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					  errmsg("invalid input syntax for type macaddr8: \"%s\"", str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("00-00-00-00-00-00-00-00 address is a reserved address")));
+
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("FF-FF-FF-FF-FF-FF-FF-FF address is a reserved address")));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+
+	if (!eight_byte_address)
+	{
+		result->d = 0xFF;
+		result->e = 0xFE;
+		result->f = d;
+		result->g = e;
+		result->h = f;
+	}
+	else
+	{
+		result->d = d;
+		result->e = e;
+		result->f = f;
+		result->g = g;
+		result->h = h;
+	}
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	MAC8 address (EUI-64) output function.  Fixed format.
+ */
+
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				addr->a, addr->b, addr->c, addr->d,
+				addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *	macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8    *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ *		macaddr8_send			- converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr8_cmp_internal(macaddr8 *a1, macaddr8 *a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else if (lobits_extra(a1) < lobits_extra(a2))
+		return -1;
+	else if (lobits_extra(a1) > lobits_extra(a2))
+		return 1;
+	else
+	{
+		return 0;
+	}
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8    *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing macaddr8 manufacturers.
+ *	From suggestion by Alex Pilosov <alex@pilosoft.com>
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..912a0a1 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,19 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8    *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 16) | (mac->b << 8) | (mac->c);
+				res *= 256 * 256 * 256;
+				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
+				res *= 256 * 256;
+				res += (mac->g << 8) | (mac->h);
+
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 56943f2..9eb0230 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3784,6 +3784,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index e4c3515..bb7c7bb 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	5002	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	5002	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	5002	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	5002	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	5002	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f01a5b4..6fcf715 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 3358 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	5002   774	 774  1  3383 ));
+DATA(insert (	5002   774	 774  2  3384 ));
+DATA(insert (	5002   774	 774  3  3385 ));
+DATA(insert (	5002   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 04d11c0..b42f619 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,13 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ *
+ * macaddr to macaddr8
+ */
+DATA(insert (  829	774    3373 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index ade8da3..8eb355e 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -125,8 +125,10 @@ DATA(insert OID = 3124 ( 403	int8_ops	PGNSP PGUID 1976   20 t 0 ));
 DATA(insert (	405		int8_ops			PGNSP PGUID 1977   20 t 0 ));
 DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
-DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
-DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr_ops		PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (	405		macaddr_ops		PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops	PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops	PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 5002   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 26fa618..6e75fc8 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1113,7 +1113,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1134,6 +1134,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 7ba23e5..f7c7b72 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 5002 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 047a1ce..800591e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1,5 +1,4 @@
-/*-------------------------------------------------------------------------
- *
+/*
  * pg_proc.h
  *	  definition of the system "procedure" relation (pg_proc)
  *	  along with the relation's initial contents.
@@ -692,6 +691,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2092,14 +2093,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2113,6 +2114,29 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 3349 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3350 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 3351 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 3352 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3353 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 3354 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 3355 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 3356 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 3357 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 3358 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 3359 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 3360 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 3361 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 3373 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4042,6 +4066,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr8_recv	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr8_send	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 162239c..81da9b8 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,9 +441,13 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8    PGNSP PGUID	8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -482,6 +486,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8	 PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 90f5132..8fd7839 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1021,6 +1021,25 @@ extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
+/* mac8.c */
+extern Datum macaddr8_in(PG_FUNCTION_ARGS);
+extern Datum macaddr8_out(PG_FUNCTION_ARGS);
+extern Datum macaddr8_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr8_send(PG_FUNCTION_ARGS);
+extern Datum macaddr8_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr8_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_le(PG_FUNCTION_ARGS);
+extern Datum macaddr8_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr8_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr8_not(PG_FUNCTION_ARGS);
+extern Datum macaddr8_and(PG_FUNCTION_ARGS);
+extern Datum macaddr8_or(PG_FUNCTION_ARGS);
+extern Datum macaddr8_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddrtomacaddr8(PG_FUNCTION_ARGS);
+
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
 extern Datum numeric_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 9fd954d..ac54304 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..e0cafd3
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,255 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr FROM macaddr8_data WHERE a = 1; -- Error
+ERROR:  cannot cast type macaddr8 to macaddr
+LINE 1: SELECT b::macaddr FROM macaddr8_data WHERE a = 1;
+                ^
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8641769..21e7f56 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 835cf35..f72fb52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..10b1108
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,61 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr FROM macaddr8_data WHERE a = 1; -- Error
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#43Tom Lane
tgl@sss.pgh.pa.us
In reply to: Haribabu Kommi (#42)
Re: macaddr 64 bit (EUI-64) datatype support

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Currently the casting is supported from macaddr to macaddr8, but not the
other way. This is because, not all 8 byte MAC addresses can be converted
into 6 byte addresses.

Well, yeah, so you'd throw an error if it can't be converted. This is
no different from casting int8 to int4, for example. We don't refuse
to provide that cast just because it will fail for some values.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#44Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Tom Lane (#43)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Sat, Nov 26, 2016 at 4:48 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Currently the casting is supported from macaddr to macaddr8, but not the
other way. This is because, not all 8 byte MAC addresses can be converted
into 6 byte addresses.

Well, yeah, so you'd throw an error if it can't be converted. This is
no different from casting int8 to int4, for example. We don't refuse
to provide that cast just because it will fail for some values.

Updated patch attached with added cast function from macaddr8 to
macaddr.

Currently there are no support for cross operators. Is this required
to be this patch only or can be handled later if required?

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_3.patchapplication/octet-stream; name=mac_eui64_support_3.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index e8a5622..479b751 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 67d0c34..8d29e52 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -165,6 +165,12 @@
        <entry></entry>
        <entry>MAC (Media Access Control) address</entry>
       </row>
+      
+      <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
 
       <row>
        <entry><type>money</type></entry>
@@ -3459,6 +3465,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>6 bytes</entry>
         <entry>MAC addresses</entry>
        </row>
+       
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
 
       </tbody>
      </tgroup>
@@ -3700,6 +3712,52 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses.
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+    
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+
+    <para>
+     The remaining six input formats are not part of any standard.
+    </para>
+   </sect2>
+   
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2e64cc4..eed1695 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9224,6 +9224,51 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 3 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 3 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    lexicographical ordering, and the bitwise arithmetic operators
+    (<literal>~</literal>, <literal>&amp;</literal> and <literal>|</literal>)
+    for NOT, AND and OR.
+   </para>
+   
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 509315a..ef0810e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..391a67a
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,469 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *  The following code is written with the assumption of
+ *  OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->g<<8)|((addr)->h))
+
+/*
+ *	MAC address (EUI-48 and EUI-64) reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8    *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g = 0,
+				h = 0;
+	char		junk[2];
+	int			count;
+	bool 		eight_byte_address = false;
+
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		eight_byte_address = true;
+
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					  errmsg("invalid input syntax for type macaddr8: \"%s\"", str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("00-00-00-00-00-00-00-00 address is a reserved address")));
+
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("FF-FF-FF-FF-FF-FF-FF-FF address is a reserved address")));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+
+	if (!eight_byte_address)
+	{
+		result->d = 0xFF;
+		result->e = 0xFE;
+		result->f = d;
+		result->g = e;
+		result->h = f;
+	}
+	else
+	{
+		result->d = d;
+		result->e = e;
+		result->f = f;
+		result->g = g;
+		result->h = h;
+	}
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	MAC8 address (EUI-64) output function.  Fixed format.
+ */
+
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				addr->a, addr->b, addr->c, addr->d,
+				addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *	macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8    *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ *		macaddr8_send			- converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr8_cmp_internal(macaddr8 *a1, macaddr8 *a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else if (lobits_extra(a1) < lobits_extra(a2))
+		return -1;
+	else if (lobits_extra(a1) > lobits_extra(a2))
+		return 1;
+	else
+	{
+		return 0;
+	}
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8    *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing macaddr8 manufacturers.
+ *	From suggestion by Alex Pilosov <alex@pilosoft.com>
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 out of range to convert to macaddr")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..912a0a1 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,19 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8    *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 16) | (mac->b << 8) | (mac->c);
+				res *= 256 * 256 * 256;
+				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
+				res *= 256 * 256;
+				res += (mac->g << 8) | (mac->h);
+
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 56943f2..9eb0230 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3784,6 +3784,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index e4c3515..bb7c7bb 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	5002	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	5002	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	5002	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	5002	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	5002	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f01a5b4..6fcf715 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 3358 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	5002   774	 774  1  3383 ));
+DATA(insert (	5002   774	 774  2  3384 ));
+DATA(insert (	5002   774	 774  3  3385 ));
+DATA(insert (	5002   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 04d11c0..460dd50 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    3373 i f ));
+DATA(insert (  774  829	   3374 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index ade8da3..8eb355e 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -125,8 +125,10 @@ DATA(insert OID = 3124 ( 403	int8_ops	PGNSP PGUID 1976   20 t 0 ));
 DATA(insert (	405		int8_ops			PGNSP PGUID 1977   20 t 0 ));
 DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
-DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
-DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr_ops		PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (	405		macaddr_ops		PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops	PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops	PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 5002   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 26fa618..6e75fc8 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1113,7 +1113,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1134,6 +1134,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 7ba23e5..f7c7b72 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 5002 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 047a1ce..b0d0408 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1,5 +1,4 @@
-/*-------------------------------------------------------------------------
- *
+/*
  * pg_proc.h
  *	  definition of the system "procedure" relation (pg_proc)
  *	  along with the relation's initial contents.
@@ -692,6 +691,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2092,14 +2093,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2113,6 +2114,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 3349 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3350 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 3351 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 3352 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 3353 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 3354 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 3355 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 3356 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 3357 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 3358 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 3359 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 3360 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 3361 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 3373 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 3374 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4042,6 +4068,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr8_recv	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr8_send	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 162239c..81da9b8 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,9 +441,13 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8    PGNSP PGUID	8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -482,6 +486,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8	 PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 90f5132..8fd7839 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1021,6 +1021,25 @@ extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
+/* mac8.c */
+extern Datum macaddr8_in(PG_FUNCTION_ARGS);
+extern Datum macaddr8_out(PG_FUNCTION_ARGS);
+extern Datum macaddr8_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr8_send(PG_FUNCTION_ARGS);
+extern Datum macaddr8_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr8_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_le(PG_FUNCTION_ARGS);
+extern Datum macaddr8_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr8_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr8_not(PG_FUNCTION_ARGS);
+extern Datum macaddr8_and(PG_FUNCTION_ARGS);
+extern Datum macaddr8_or(PG_FUNCTION_ARGS);
+extern Datum macaddr8_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddrtomacaddr8(PG_FUNCTION_ARGS);
+
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
 extern Datum numeric_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 9fd954d..ac54304 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8641769..21e7f56 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 835cf35..f72fb52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#45Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Haribabu Kommi (#44)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Nov 29, 2016 at 8:36 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

On Sat, Nov 26, 2016 at 4:48 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Haribabu Kommi <kommi.haribabu@gmail.com> writes:

Currently the casting is supported from macaddr to macaddr8, but not the
other way. This is because, not all 8 byte MAC addresses can be

converted

into 6 byte addresses.

Well, yeah, so you'd throw an error if it can't be converted. This is
no different from casting int8 to int4, for example. We don't refuse
to provide that cast just because it will fail for some values.

Updated patch attached with added cast function from macaddr8 to
macaddr.

Currently there are no support for cross operators. Is this required
to be this patch only or can be handled later if required?

Updated patch attached to address the duplicate OID problem.
There are no other functional changes to the previous patch.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_4.patchapplication/octet-stream; name=mac_eui64_support_4.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 464ce83..f5f2098 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -165,6 +165,12 @@
        <entry></entry>
        <entry>MAC (Media Access Control) address</entry>
       </row>
+      
+      <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
 
       <row>
        <entry><type>money</type></entry>
@@ -3459,6 +3465,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>6 bytes</entry>
         <entry>MAC addresses</entry>
        </row>
+       
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
 
       </tbody>
      </tgroup>
@@ -3700,6 +3712,52 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses.
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+    
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+
+    <para>
+     The remaining six input formats are not part of any standard.
+    </para>
+   </sect2>
+   
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 10e3186..5e472ce 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,51 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 3 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 3 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    lexicographical ordering, and the bitwise arithmetic operators
+    (<literal>~</literal>, <literal>&amp;</literal> and <literal>|</literal>)
+    for NOT, AND and OR.
+   </para>
+   
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 509315a..ef0810e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..391a67a
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,469 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *  The following code is written with the assumption of
+ *  OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->g<<8)|((addr)->h))
+
+/*
+ *	MAC address (EUI-48 and EUI-64) reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8    *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g = 0,
+				h = 0;
+	char		junk[2];
+	int			count;
+	bool 		eight_byte_address = false;
+
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+				&a, &b, &c, &d, &e, &f, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		eight_byte_address = true;
+
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+					  errmsg("invalid input syntax for type macaddr8: \"%s\"", str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("00-00-00-00-00-00-00-00 address is a reserved address")));
+
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+			   errmsg("invalid \"macaddr8\" Address: \"%s\"", str),
+			   errhint ("FF-FF-FF-FF-FF-FF-FF-FF address is a reserved address")));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+
+	if (!eight_byte_address)
+	{
+		result->d = 0xFF;
+		result->e = 0xFE;
+		result->f = d;
+		result->g = e;
+		result->h = f;
+	}
+	else
+	{
+		result->d = d;
+		result->e = e;
+		result->f = f;
+		result->g = g;
+		result->h = h;
+	}
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	MAC8 address (EUI-64) output function.  Fixed format.
+ */
+
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				addr->a, addr->b, addr->c, addr->d,
+				addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *	macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8    *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ *		macaddr8_send			- converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr8_cmp_internal(macaddr8 *a1, macaddr8 *a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else if (lobits_extra(a1) < lobits_extra(a2))
+		return -1;
+	else if (lobits_extra(a1) > lobits_extra(a2))
+		return 1;
+	else
+	{
+		return 0;
+	}
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8    *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8    *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing macaddr8 manufacturers.
+ *	From suggestion by Alex Pilosov <alex@pilosoft.com>
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8    *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8    *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 out of range to convert to macaddr")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..912a0a1 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,19 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8    *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 16) | (mac->b << 8) | (mac->c);
+				res *= 256 * 256 * 256;
+				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
+				res *= 256 * 256;
+				res += (mac->g << 8) | (mac->h);
+
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 301dffa..e482b3d 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3798,6 +3798,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..f6d3a5b 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774  829	   4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5d22c87 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -125,8 +125,10 @@ DATA(insert OID = 3124 ( 403	int8_ops	PGNSP PGUID 1976   20 t 0 ));
 DATA(insert (	405		int8_ops			PGNSP PGUID 1977   20 t 0 ));
 DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
-DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
-DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr_ops		PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (	405		macaddr_ops		PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops	PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops	PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index aeb7927..c5c1e5e 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1113,7 +1113,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1134,6 +1134,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 37e022d..bc68f61 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1,5 +1,4 @@
-/*-------------------------------------------------------------------------
- *
+/*
  * pg_proc.h
  *	  definition of the system "procedure" relation (pg_proc)
  *	  along with the relation's initial contents.
@@ -692,6 +691,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2094,14 +2095,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2115,6 +2116,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4044,6 +4070,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr8_recv	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr8_send	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c2350f3..b01a877 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,9 +441,13 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8    PGNSP PGUID	8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -482,6 +486,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8	 PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e1bb344..f8c7faa 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1022,6 +1022,26 @@ extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
+/* mac8.c */
+extern Datum macaddr8_in(PG_FUNCTION_ARGS);
+extern Datum macaddr8_out(PG_FUNCTION_ARGS);
+extern Datum macaddr8_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr8_send(PG_FUNCTION_ARGS);
+extern Datum macaddr8_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr8_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_le(PG_FUNCTION_ARGS);
+extern Datum macaddr8_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr8_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr8_not(PG_FUNCTION_ARGS);
+extern Datum macaddr8_and(PG_FUNCTION_ARGS);
+extern Datum macaddr8_or(PG_FUNCTION_ARGS);
+extern Datum macaddr8_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddrtomacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddr8tomacaddr(PG_FUNCTION_ARGS);
+
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
 extern Datum numeric_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index f6d4072..c9a8d66 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8641769..21e7f56 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 835cf35..f72fb52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#46Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Haribabu Kommi (#45)
Re: macaddr 64 bit (EUI-64) datatype support

On 1/4/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

On Tue, Nov 29, 2016 at 8:36 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Updated patch attached with added cast function from macaddr8 to
macaddr.

Currently there are no support for cross operators. Is this required
to be this patch only or can be handled later if required?

Updated patch attached to address the duplicate OID problem.
There are no other functional changes to the previous patch.

Hello,

several thoughts about the patch:

Documentation:
1.
+ The remaining six input formats are not part of any standard.
Which ones (remaining six formats)?

2.
+ <function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 3 bytes set to zero.
It is a misprinting or a copy-paste error.
The implementation and the standard says that the last five bytes are
set to zero and the first three are left as is.

3.
+ for lexicographical ordering
I'm not a native English speaker, but I'd say just "for ordering"
since there are no words, it is just a big number with a special
input/output format.

The code:
4.
+	if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+			&& (e == 0) && (f == 0) && (g == 0) && (h == 0))
...
+	if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+			&& (e == 255) && (f == 255) && (g == 255) && (h == 255))
The standard forbids these values from using in real hardware, no
reason to block them as input data.
Moreover these values can be stored as a result of binary operations,
users can dump them but can not restore.
5.
+	if (!eight_byte_address)
+	{
+		result->d = 0xFF;
...

Don't you think the next version is simplier (all sscanf for macaddr6
skip "d" and "e")?

+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
...
+	if (!eight_byte_address)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
Also:
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+		addr->f = pq_getmsgbyte(buf);
+		addr->g = pq_getmsgbyte(buf);
+		addr->h = pq_getmsgbyte(buf);
+	}
can be written as:
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);

but it is only my point of view (don't need to pay close attention
that only those two bytes are written differently, not the last tree
ones), it is not an error.

6.
+ errmsg("macaddr8 out of range to convert to macaddr")));
I think a hint should be added which values are allowed to convert to "macaddr".

7.
+DATA(insert ( 829 774 4123 i f ));
+DATA(insert ( 774 829 4124 i f ));
It is a nitpicking, but try to use tabs as in the code around.
(tab between "774" and "829" and space instead of tab between "829" and "4124").

8.
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->g<<8)|((addr)->h))

I mentioned that fitting all 4 bytes is a wrong idea[1]/messages/by-id/CAKOSWNng9_+=FVO6OZ4TGv1KKHmoM11anKihBoKPuZki1cAkLQ@mail.gmail.com

The macros "hibits" should be 3 octets long, not 4;

... but now I do not think so (there is no UB[2]http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1817.htm because source and
destination are not signed).
Moreover you've already fill in "hibits" the topmost byte by shifting by 24.
If you use those two macros ("hibits" and "lobits") it allows to avoid
two extra comparisons in macaddr8_cmp_internal.
Version from the "macaddr64_poc.patch" is correct.

[1]: /messages/by-id/CAKOSWNng9_+=FVO6OZ4TGv1KKHmoM11anKihBoKPuZki1cAkLQ@mail.gmail.com
[2]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1817.htm

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#47Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#46)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Fri, Jan 6, 2017 at 3:51 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 1/4/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

On Tue, Nov 29, 2016 at 8:36 PM, Haribabu Kommi <

kommi.haribabu@gmail.com>

wrote:

Updated patch attached with added cast function from macaddr8 to
macaddr.

Currently there are no support for cross operators. Is this required
to be this patch only or can be handled later if required?

Updated patch attached to address the duplicate OID problem.
There are no other functional changes to the previous patch.

Hello,

several thoughts about the patch:

Thanks for the review.

Documentation:
1.
+ The remaining six input formats are not part of any standard.
Which ones (remaining six formats)?

Updated the documentation to point to correct six formats.

2.

+ <function>trunc(<type>macaddr8</type>)</function></literal> returns a
MAC
+   address with the last 3 bytes set to zero.
It is a misprinting or a copy-paste error.
The implementation and the standard says that the last five bytes are
set to zero and the first three are left as is.

Fixed.

3.
+ for lexicographical ordering
I'm not a native English speaker, but I'd say just "for ordering"
since there are no words, it is just a big number with a special
input/output format.

Changed accordingly.

The code:
4.
+       if ((a == 0) && (b == 0) && (c == 0) && (d == 0)
+                       && (e == 0) && (f == 0) && (g == 0) && (h == 0))
...
+       if ((a == 255) && (b == 255) && (c == 255) && (d == 255)
+                       && (e == 255) && (f == 255) && (g == 255) && (h ==
255))
The standard forbids these values from using in real hardware, no
reason to block them as input data.
Moreover these values can be stored as a result of binary operations,
users can dump them but can not restore.

Ok. Removed the above code that blocks the input.

5.
+       if (!eight_byte_address)
+       {
+               result->d = 0xFF;
...

Don't you think the next version is simplier (all sscanf for macaddr6
skip "d" and "e")?

+       count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+                                  &a, &b, &c, &f, &g, &h, junk);
...
+       if (!eight_byte_address)
+       {
+               d = 0xFF;
+               e = 0xFE;
+       }
+       result->a = a;
+       result->b = b;
+       result->c = c;
+       result->d = d;
+       result->e = e;
+       result->f = f;
+       result->g = g;
+       result->h = h;
Also:
+       if (buf->len == 6)
+       {
+               addr->d = 0xFF;
+               addr->e = 0xFE;
+               addr->f = pq_getmsgbyte(buf);
+               addr->g = pq_getmsgbyte(buf);
+               addr->h = pq_getmsgbyte(buf);
+       }
+       else
+       {
+               addr->d = pq_getmsgbyte(buf);
+               addr->e = pq_getmsgbyte(buf);
+               addr->f = pq_getmsgbyte(buf);
+               addr->g = pq_getmsgbyte(buf);
+               addr->h = pq_getmsgbyte(buf);
+       }
can be written as:
+       if (buf->len == 6)
+       {
+               addr->d = 0xFF;
+               addr->e = 0xFE;
+       }
+       else
+       {
+               addr->d = pq_getmsgbyte(buf);
+               addr->e = pq_getmsgbyte(buf);
+       }
+       addr->f = pq_getmsgbyte(buf);
+       addr->g = pq_getmsgbyte(buf);
+       addr->h = pq_getmsgbyte(buf);

but it is only my point of view (don't need to pay close attention
that only those two bytes are written differently, not the last tree
ones), it is not an error.

Updated as per you suggestion.

6.
+ errmsg("macaddr8 out of range to convert
to macaddr")));
I think a hint should be added which values are allowed to convert to
"macaddr".

Added the hint message to explain in detail about addresses that are
eligible for
conversion from macaddr8 type to macaddr.

7.

+DATA(insert (  829     774    4123 i f ));
+DATA(insert (  774  829           4124 i f ));
It is a nitpicking, but try to use tabs as in the code around.
(tab between "774" and "829" and space instead of tab between "829" and
"4124").

Done the indentation to correct the problem.

8.
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
+
+#define lobits_extra(addr) \
+  ((unsigned long)((addr)->g<<8)|((addr)->h))

I mentioned that fitting all 4 bytes is a wrong idea[1]

The macros "hibits" should be 3 octets long, not 4;

... but now I do not think so (there is no UB[2] because source and
destination are not signed).
Moreover you've already fill in "hibits" the topmost byte by shifting by
24.
If you use those two macros ("hibits" and "lobits") it allows to avoid
two extra comparisons in macaddr8_cmp_internal.
Version from the "macaddr64_poc.patch" is correct.

[1]/messages/by-id/CAKOSWNng9_+=
FVO6OZ4TGv1KKHmoM11anKihBoKPuZki1cAkLQ@mail.gmail.com
[2]http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1817.htm

Corrected.

Updated patch is attached.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_5.patchapplication/octet-stream; name=mac_eui64_support_5.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3bc6854..c86e5fd 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -165,6 +165,12 @@
        <entry></entry>
        <entry>MAC (Media Access Control) address</entry>
       </row>
+      
+      <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
 
       <row>
        <entry><type>money</type></entry>
@@ -3460,6 +3466,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>6 bytes</entry>
         <entry>MAC addresses</entry>
        </row>
+       
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
 
       </tbody>
      </tgroup>
@@ -3701,6 +3713,53 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses.
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+    
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+   
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 10e3186..0b74d40 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+	<literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+   
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 509315a..ef0810e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..682ce07
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,441 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *	The following code is written with the assumption of
+ *	OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)|((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24)|((addr)->f<<16)|((addr)->g<<8)|((addr)->h)))
+
+/*
+ *	MAC address (EUI-48 and EUI-64) reader.  Accepts several common notations.
+ */
+
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d = 0,
+				e = 0,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+	bool		eight_byte_address = false;
+
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		eight_byte_address = true;
+
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			 errmsg("invalid input syntax for type macaddr8: \"%s\"", str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	if (!eight_byte_address)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	MAC8 address (EUI-64) output function.  Fixed format.
+ */
+
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ *	macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the six bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ *		macaddr8_send			- converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ *	Comparison function for sorting:
+ */
+
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ *	Boolean comparisons.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ *	Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..1719f01 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,17 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= 256 * 256;
+				res *= 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 301dffa..e482b3d 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3798,6 +3798,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5d22c87 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -125,8 +125,10 @@ DATA(insert OID = 3124 ( 403	int8_ops	PGNSP PGUID 1976   20 t 0 ));
 DATA(insert (	405		int8_ops			PGNSP PGUID 1977   20 t 0 ));
 DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
-DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
-DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr_ops		PGNSP PGUID 1984  829 t 0 ));
+DATA(insert (	405		macaddr_ops		PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops	PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops	PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index aeb7927..c5c1e5e 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1113,7 +1113,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1134,6 +1134,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 37e022d..8ec5bc7 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1,5 +1,4 @@
-/*-------------------------------------------------------------------------
- *
+/*
  * pg_proc.h
  *	  definition of the system "procedure" relation (pg_proc)
  *	  along with the relation's initial contents.
@@ -692,6 +691,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -1765,7 +1766,7 @@ DATA(insert OID = 1765 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20
 DESCR("set sequence value and is_called status");
 DATA(insert OID = 3078 (  pg_sequence_parameters	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16,20}" "{i,o,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option,cache_size}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_));
 DESCR("sequence parameters, for use by information schema");
-DATA(insert OID = 4032 ( pg_sequence_last_value		PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_	pg_sequence_last_value _null_ _null_ _null_ ));
+DATA(insert OID = 4032 ( pg_sequence_last_value		PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_ pg_sequence_last_value _null_ _null_ _null_ ));
 DESCR("sequence last value");
 
 DATA(insert OID = 1579 (  varbit_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ));
@@ -1979,7 +1980,7 @@ DATA(insert OID = 1642 (  pg_get_userbyid	   PGNSP PGUID 12 1 0 0 0 f f f f t f
 DESCR("role name by OID (with fallback)");
 DATA(insert OID = 1643 (  pg_get_indexdef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_indexdef _null_ _null_ _null_ ));
 DESCR("index description");
-DATA(insert OID = 3352 (  pg_get_partkeydef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_partkeydef _null_ _null_ _null_ ));
+DATA(insert OID = 3352 (  pg_get_partkeydef    PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_partkeydef _null_ _null_ _null_ ));
 DESCR("partition key description");
 DATA(insert OID = 1662 (  pg_get_triggerdef    PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 25 "26" _null_ _null_ _null_ _null_ _null_ pg_get_triggerdef _null_ _null_ _null_ ));
 DESCR("trigger description");
@@ -2094,14 +2095,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2115,6 +2116,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4044,6 +4070,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3344 (  macaddr8_recv    PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3345 (  macaddr8_send    PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c2350f3..b3fc4ec 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,9 +441,13 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
+
 /* OIDS 1000 - 1099 */
 DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b A f t \054 0	16 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b A f t \054 0	17 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -482,6 +486,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index e1bb344..f8c7faa 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1022,6 +1022,26 @@ extern Datum macaddr_or(PG_FUNCTION_ARGS);
 extern Datum macaddr_trunc(PG_FUNCTION_ARGS);
 extern Datum hashmacaddr(PG_FUNCTION_ARGS);
 
+/* mac8.c */
+extern Datum macaddr8_in(PG_FUNCTION_ARGS);
+extern Datum macaddr8_out(PG_FUNCTION_ARGS);
+extern Datum macaddr8_recv(PG_FUNCTION_ARGS);
+extern Datum macaddr8_send(PG_FUNCTION_ARGS);
+extern Datum macaddr8_cmp(PG_FUNCTION_ARGS);
+extern Datum macaddr8_lt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_le(PG_FUNCTION_ARGS);
+extern Datum macaddr8_eq(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ge(PG_FUNCTION_ARGS);
+extern Datum macaddr8_gt(PG_FUNCTION_ARGS);
+extern Datum macaddr8_ne(PG_FUNCTION_ARGS);
+extern Datum macaddr8_not(PG_FUNCTION_ARGS);
+extern Datum macaddr8_and(PG_FUNCTION_ARGS);
+extern Datum macaddr8_or(PG_FUNCTION_ARGS);
+extern Datum macaddr8_trunc(PG_FUNCTION_ARGS);
+extern Datum hashmacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddrtomacaddr8(PG_FUNCTION_ARGS);
+extern Datum macaddr8tomacaddr(PG_FUNCTION_ARGS);
+
 /* numeric.c */
 extern Datum numeric_in(PG_FUNCTION_ARGS);
 extern Datum numeric_out(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index f6d4072..c9a8d66 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8641769..21e7f56 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 835cf35..f72fb52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#48Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Haribabu Kommi (#47)
Re: macaddr 64 bit (EUI-64) datatype support

On Mon, Jan 9, 2017 at 1:45 PM, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

Updated patch is attached.

I've a few comments about the patch.

+ This type can accept both 6 and 8 bytes length MAC addresses.
A 6 bytes length MAC address is internally converted to 8 bytes. We
should include this in the docs. Because output is always 8 bytes.
Otherwise, a user may be surprised with the output.

+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)|((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24)|((addr)->f<<16)|((addr)->g<<8)|((addr)->h)))
+
There should be some spacing.
+ if (!eight_byte_address)
+ {
+ d = 0xFF;
+ e = 0xFE;
+ }
You already have count variable. Just check (count != 8).
+ res *= 256 * 256;
+ res *= 256 * 256;
Bit shift operator can be used for this. For example: (res << 32).
-DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984  829 t 0 ));
-DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985  829 t 0 ));
+DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984  829 t 0 ));
+DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985  829 t 0 ));
This is unnecessary I guess.

There was some whitespace error while applying the patch. Also, there
are some spacing inconsistencies in the comments. I've not tested with
this patch. I'll let you know once I'm done testing.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#49Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Kuntal Ghosh (#48)
1 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Sat, Jan 14, 2017 at 6:28 PM, Kuntal Ghosh <kuntalghosh.2007@gmail.com>
wrote:

On Mon, Jan 9, 2017 at 1:45 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Updated patch is attached.

I've a few comments about the patch.

Thanks for the review.

+ This type can accept both 6 and 8 bytes length MAC addresses.

A 6 bytes length MAC address is internally converted to 8 bytes. We
should include this in the docs. Because output is always 8 bytes.
Otherwise, a user may be surprised with the output.

updated accordingly.

+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24)|((addr)->b<<16)|((addr)->c<<8)|((addr)
->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24)|((addr)->f<<16)|((addr)->g<<8)|((addr)
->h)))
+
There should be some spacing.

corrected.

+ if (!eight_byte_address)

+ {
+ d = 0xFF;
+ e = 0xFE;
+ }
You already have count variable. Just check (count != 8).

Changed.

+ res *= 256 * 256;
+ res *= 256 * 256;
Bit shift operator can be used for this. For example: (res << 32).

Changed by adding a typecast, because res is a double datatype value.

-DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984  829 t 0 ));
-DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985  829 t 0 ));
+DATA(insert ( 403 macaddr_ops PGNSP PGUID 1984  829 t 0 ));
+DATA(insert ( 405 macaddr_ops PGNSP PGUID 1985  829 t 0 ));
This is unnecessary I guess.

Corrected.

There was some whitespace error while applying the patch. Also, there
are some spacing inconsistencies in the comments. I've not tested with
this patch. I'll let you know once I'm done testing.

Corrected.

Updated patch attached.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_6.patchapplication/octet-stream; name=mac_eui64_support_6.patchDownload
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3bc6854..be4374d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3461,6 +3467,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3701,6 +3713,55 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses
+     and stores it in 8 byte length format.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 2504a46..84170da 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..3a3903b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..97321d2
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,434 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *	The following code is written with the assumption of
+ *	OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d = 0,
+				e = 0,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	if (count != 8)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..832333d 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res = (double)((uint64)res << 32);
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 301dffa..e482b3d 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3798,6 +3798,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 03f55a1..a578ba0 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4048,6 +4075,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c2350f3..6218d5a5 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..27bd639 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 8641769..21e7f56 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 835cf35..f72fb52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#50Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Haribabu Kommi (#49)
Re: macaddr 64 bit (EUI-64) datatype support

On Thu, Jan 19, 2017 at 7:46 AM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:

Updated patch attached.

I've looked at the updated patch. There are still some changes that
needs to be done. It includes:

1. Adding macaddr8 support for btree_gist and testcases.
2. Implementation of macaddr8 support for btree_gin is incomplete. You
need to modify contrib/btree_gin/*.sql files as well. Also, testcases
needs to be added.

Other than that, I've tested the basic implementation of the feature.
It looks good.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#51Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Kuntal Ghosh (#50)
2 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Mon, Jan 23, 2017 at 6:29 PM, Kuntal Ghosh <kuntalghosh.2007@gmail.com>
wrote:

On Thu, Jan 19, 2017 at 7:46 AM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:

Updated patch attached.

I've looked at the updated patch. There are still some changes that
needs to be done. It includes:

Thanks for the review.

1. Adding macaddr8 support for btree_gist and testcases.

2. Implementation of macaddr8 support for btree_gin is incomplete. You
need to modify contrib/btree_gin/*.sql files as well. Also, testcases
needs to be added.

Added the support for macaddr8 datatype for both btree_gin and btree_gist
modules and the tests also.

I didn't update the *.sql files to the latest version and just added the
update *.sql
file only as like earlier changes on btree_gist for UUID support to make it
easier
for the reviewer.

The patch is split into two parts.
1. Macaddr8 datatype support
2. Contrib module support.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_7.patchapplication/octet-stream; name=mac_eui64_support_7.patchDownload
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3bc6854..be4374d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3461,6 +3467,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3701,6 +3713,55 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses
+     and stores it in 8 byte length format.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b214218..d3310f7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..3a3903b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..97321d2
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,434 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *	The following code is written with the assumption of
+ *	OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d = 0,
+				e = 0,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	if (count != 8)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..832333d 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res = (double)((uint64)res << 32);
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fa32e9e..c29ff16 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3799,6 +3799,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ab12761..8c9b236 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4050,6 +4077,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c2350f3..6218d5a5 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..27bd639 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e9b2bad..122119f 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7cdc0f6..2380120 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
contrib_macaddr8_1.patchapplication/octet-stream; name=contrib_macaddr8_1.patchDownload
diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..e9e377f
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8,macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8,macaddr8,int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..38def79 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+		btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql 
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+		bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..3bec9d0
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8		lower;
+	macaddr8		upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY	   *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY	   *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 *m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8    *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY	   *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY	   *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY	   *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
#52Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Haribabu Kommi (#51)
Re: macaddr 64 bit (EUI-64) datatype support

On 1/23/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

The patch is split into two parts.
1. Macaddr8 datatype support
2. Contrib module support.

Hello,

I'm sorry for the delay.
The patch is almost done, but I have two requests since the last review.

1.
src/backend/utils/adt/mac8.c:
+	int			a,
+				b,
+				c,
+				d = 0,
+				e = 0,
...

There is no reason to set them as 0. For EUI-48 they will be
reassigned in the "if (count != 8)" block, for EUI-64 -- in one of
sscanf.
They could be set to "d = 0xFF, e = 0xFE," and avoid the "if" block
mentioned above, but it makes the code be much less readable.

Oh. I see. In the current version it must be assigned because for
EUI-48 memory can have values <0 or >255 in uninitialized variables.
It is better to avoid initialization by merging two parts of the code:
+	if (count != 6)
+	{
+		/* May be a 8-byte MAC address */
...
+	if (count != 8)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
to a single one:
+	if (count == 6)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else
+	{
+		/* May be a 8-byte MAC address */
...
2.
src/backend/utils/adt/network.c:
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res = (double)((uint64)res << 32);
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
Khm... I trust that modern compilers can do a lot of optimizations but
for me it looks terrible because of needless conversions.
The reason why earlier versions did have two lines "res *= 256 * 256"
was an integer overflow for four multipliers, but it can be solved by
defining the first multiplier as a double:
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= (double)256 * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);

In this case the left-hand side argument for the "*=" operator is
computed at the compile time as a single constant.
The second line can be written as "res *= 256. * 256 * 256 * 256;"
(pay attention to a dot in the first multiplier), but it is not
readable at all (and produces the same code).

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#53Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#52)
2 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Jan 25, 2017 at 6:43 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 1/23/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

The patch is split into two parts.
1. Macaddr8 datatype support
2. Contrib module support.

Hello,

I'm sorry for the delay.
The patch is almost done, but I have two requests since the last review.

Thanks for the review.

1.
src/backend/utils/adt/mac8.c:
+       int                     a,
+                               b,
+                               c,
+                               d = 0,
+                               e = 0,
...

There is no reason to set them as 0. For EUI-48 they will be
reassigned in the "if (count != 8)" block, for EUI-64 -- in one of
sscanf.
They could be set to "d = 0xFF, e = 0xFE," and avoid the "if" block
mentioned above, but it makes the code be much less readable.

Oh. I see. In the current version it must be assigned because for
EUI-48 memory can have values <0 or >255 in uninitialized variables.
It is better to avoid initialization by merging two parts of the code:
+       if (count != 6)
+       {
+               /* May be a 8-byte MAC address */
...
+       if (count != 8)
+       {
+               d = 0xFF;
+               e = 0xFE;
+       }
to a single one:
+       if (count == 6)
+       {
+               d = 0xFF;
+               e = 0xFE;
+       }
+       else
+       {
+               /* May be a 8-byte MAC address */
...

Changed accordingly.

2.
src/backend/utils/adt/network.c:
+                               res = (mac->a << 24) | (mac->b << 16) |
(mac->c << 8) | (mac->d);
+                               res = (double)((uint64)res << 32);
+                               res += (mac->e << 24) | (mac->f << 16) |
(mac->g << 8) | (mac->h);
Khm... I trust that modern compilers can do a lot of optimizations but
for me it looks terrible because of needless conversions.
The reason why earlier versions did have two lines "res *= 256 * 256"
was an integer overflow for four multipliers, but it can be solved by
defining the first multiplier as a double:
+                               res = (mac->a << 24) | (mac->b << 16) |
(mac->c << 8) | (mac->d);
+                               res *= (double)256 * 256 * 256 * 256;
+                               res += (mac->e << 24) | (mac->f << 16) |
(mac->g << 8) | (mac->h);

In this case the left-hand side argument for the "*=" operator is
computed at the compile time as a single constant.
The second line can be written as "res *= 256. * 256 * 256 * 256;"
(pay attention to a dot in the first multiplier), but it is not
readable at all (and produces the same code).

Corrected as suggested.

Updated patch attached. There is no change in the contrib patch.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_8.patchapplication/octet-stream; name=mac_eui64_support_8.patchDownload
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3bc6854..be4374d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3461,6 +3467,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3701,6 +3713,55 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses
+     and stores it in 8 byte length format.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b214218..d3310f7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..3a3903b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..65dad05
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,433 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *	The following code is written with the assumption of
+ *	OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d = 0,
+				e = 0,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count == 6)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else
+	{
+		/* May be a 8-byte MAC address */
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..df51cfa 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= (double)256 * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fa32e9e..c29ff16 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3799,6 +3799,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c1f492b..5e7fa18 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4050,6 +4077,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index c2350f3..6218d5a5 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..27bd639 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e9b2bad..122119f 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7cdc0f6..2380120 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
contrib_macaddr8_1.patchapplication/octet-stream; name=contrib_macaddr8_1.patchDownload
diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..e9e377f
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8,macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8,macaddr8,int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..38def79 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+		btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql 
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+		bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..3bec9d0
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8		lower;
+	macaddr8		upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY	   *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY	   *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 *m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8    *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY	   *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY	   *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY	   *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
#54Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Haribabu Kommi (#53)
Re: macaddr 64 bit (EUI-64) datatype support

On 1/25/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

On Wed, Jan 25, 2017 at 6:43 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 1/23/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

The patch is split into two parts.
1. Macaddr8 datatype support
2. Contrib module support.

Hello,

I'm sorry for the delay.
The patch is almost done, but I have two requests since the last review.

Thanks for the review.

1.
src/backend/utils/adt/mac8.c:
+       int                     a,
+                               b,
+                               c,
+                               d = 0,
+                               e = 0,
...

There is no reason to set them as 0. For EUI-48 they will be
reassigned in the "if (count != 8)" block, for EUI-64 -- in one of
sscanf.
They could be set to "d = 0xFF, e = 0xFE," and avoid the "if" block
mentioned above, but it makes the code be much less readable.

<overquoted>

Changed accordingly.

I'm going to do (I hope) a final review tonight.
Please, remove initialization of the variables "d" and "e" since there
is really no reason to keep them be zero for a short time.

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#55Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Haribabu Kommi (#53)
Re: macaddr 64 bit (EUI-64) datatype support

On Wed, Jan 25, 2017 at 6:00 PM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:

Corrected as suggested.

Updated patch attached. There is no change in the contrib patch.

Got whitspace error warning while applying contrib_macaddr8_1.patch:184.

diff --git a/contrib/btree_gist/btree_gist.control
b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
btree_gin.control should be updated as well. Otherwise, make
check-world is throwing error.

After making the above changes, I'm able to run regression test
successfully without any error/warning.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#56Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#54)
Re: macaddr 64 bit (EUI-64) datatype support

On Thu, Jan 26, 2017 at 9:42 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 1/25/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

On Wed, Jan 25, 2017 at 6:43 PM, Vitaly Burovoy <

vitaly.burovoy@gmail.com>

wrote:

I'm going to do (I hope) a final review tonight.
Please, remove initialization of the variables "d" and "e" since there
is really no reason to keep them be zero for a short time.

Thanks for the review. Corrected in the latest patch.

Regards,
Hari Babu
Fujitsu Australia

#57Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Kuntal Ghosh (#55)
2 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Fri, Jan 27, 2017 at 6:10 PM, Kuntal Ghosh <kuntalghosh.2007@gmail.com>
wrote:

On Wed, Jan 25, 2017 at 6:00 PM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:

Corrected as suggested.

Updated patch attached. There is no change in the contrib patch.

Got whitspace error warning while applying contrib_macaddr8_1.patch:184.

Corrected.

diff --git a/contrib/btree_gist/btree_gist.control
b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
# btree_gist extension
comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
btree_gin.control should be updated as well. Otherwise, make
check-world is throwing error.

After making the above changes, I'm able to run regression test
successfully without any error/warning.

Corrected the change in btree_gin.control file also.
Thanks for the review.

Updated patches are attached.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

mac_eui64_support_9.patchapplication/octet-stream; name=mac_eui64_support_9.patchDownload
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 9ef7b4a..3025abf 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3461,6 +3467,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3701,6 +3713,55 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses
+     and stores it in 8 byte length format.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b214218..d3310f7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..3a3903b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..7d11230
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,433 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses
+ *	Support both EUI-48 and EUI-64.
+ *
+ *	The following code is written with the assumption of
+ *	OUI field size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count == 6)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else
+	{
+		/* May be a 8-byte MAC address */
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..df51cfa 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= (double)256 * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fa32e9e..c29ff16 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3799,6 +3799,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..6d73d98 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 31c828a..fdfabdc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4050,6 +4077,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 6e4c65e..1358a99 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 972
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..27bd639 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)    ((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)    PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e9b2bad..122119f 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7cdc0f6..2380120 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
contrib_macaddr8_2.patchapplication/octet-stream; name=contrib_macaddr8_2.patchDownload
diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..e9e377f
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8,macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8,macaddr8,int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..d5c0e49 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8    *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d..d96436e 100644
--- a/contrib/btree_gin/btree_gin.control
+++ b/contrib/btree_gin/btree_gin.control
@@ -1,5 +1,5 @@
 # btree_gin extension
 comment = 'support for indexing common datatypes in GIN'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/btree_gin'
 relocatable = true
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..db72db3 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+		btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+		bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..3bec9d0
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8		lower;
+	macaddr8		upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY	   *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY	   *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 *m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8    *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY	   *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY	   *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY	   *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY	   *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
#58Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Haribabu Kommi (#57)
Re: macaddr 64 bit (EUI-64) datatype support

On 1/27/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

Updated patches are attached.

Hello,

I'm almost ready to mark it as Ready for committer.
The final round.

1.

+DATA(insert OID = 774 ( macaddr8 ...
+#define MACADDR8OID 972

What does this number (972) mean? I think it should be 774, the same
number as was used in the type definition.

Since there is an editing required, please, fix whitespaces:
2.

+DATA(insert OID = 3371 (	403		macaddr8_ops			PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops			PGNSP PGUID ));

only one (not three) tab before "PGNSP" should be used (see other rows
around yours: "OID = 1983", "OID = 1991" etc).

3.

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile

some new rows have two tabs instead of eight spaces.

4.
Some other files need to be fixed by pgindent (it helps supporting in
the future):
contrib/btree_gist/btree_macaddr8.c (a lot of rows)
src/include/utils/inet.h (I have no idea why it changes indentation
to tabs for macaddr8 whereas it leaves spaces for macaddr)

5.
src/backend/utils/adt/network.c
pg_indent makes it uglier. I've just found how to write the line for it:
res *= ((double) 256) * 256 * 256 * 256;

--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#59Michael Paquier
michael.paquier@gmail.com
In reply to: Vitaly Burovoy (#58)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Jan 31, 2017 at 2:13 PM, Vitaly Burovoy
<vitaly.burovoy@gmail.com> wrote:

I'm almost ready to mark it as Ready for committer.
The final round.

Moved to next CF with same status, waiting on author as the last patch
and the last review are very fresh.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#60Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#58)
2 attachment(s)
Re: macaddr 64 bit (EUI-64) datatype support

On Tue, Jan 31, 2017 at 4:13 PM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

On 1/27/17, Haribabu Kommi <kommi.haribabu@gmail.com> wrote:

Updated patches are attached.

Hello,

I'm almost ready to mark it as Ready for committer.
The final round.

Thanks for the review.

1.

+DATA(insert OID = 774 ( macaddr8 ...
+#define MACADDR8OID 972

What does this number (972) mean? I think it should be 774, the same
number as was used in the type definition.

I think I might have missed to update during OID number changes.
Fixed.

Since there is an editing required, please, fix whitespaces:
2.

+DATA(insert OID = 3371 ( 403 macaddr8_ops

PGNSP PGUID ));

+DATA(insert OID = 3372 ( 405 macaddr8_ops

PGNSP PGUID ));

only one (not three) tab before "PGNSP" should be used (see other rows
around yours: "OID = 1983", "OID = 1991" etc).

Corrected.

3.

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile

some new rows have two tabs instead of eight spaces.

Corrected.

4.
Some other files need to be fixed by pgindent (it helps supporting in
the future):
contrib/btree_gist/btree_macaddr8.c (a lot of rows)
src/include/utils/inet.h (I have no idea why it changes indentation
to tabs for macaddr8 whereas it leaves spaces for macaddr)

Done.

5.

src/backend/utils/adt/network.c
pg_indent makes it uglier. I've just found how to write the line for it:
res *= ((double) 256) * 256 * 256 * 256;

Done.

Updated patches are attached.

Regards,
Hari Babu
Fujitsu Australia

Attachments:

contrib_macaddr8_3.patchapplication/octet-stream; name=contrib_macaddr8_3.patchDownload
diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..e9e377f
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8,macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8,macaddr8,int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..725456e 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8   *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d..d96436e 100644
--- a/contrib/btree_gin/btree_gin.control
+++ b/contrib/btree_gin/btree_gin.control
@@ -1,5 +1,5 @@
 # btree_gin extension
 comment = 'support for indexing common datatypes in GIN'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/btree_gin'
 relocatable = true
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..c70f178 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+        btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+        bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..c463bca
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8	lower;
+	macaddr8	upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY    *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY    *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 * m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8   *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY    *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY    *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY    *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
mac_eui64_support_10.patchapplication/octet-stream; name=mac_eui64_support_10.patchDownload
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index f519285..7c603e2 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 9ef7b4a..3025abf 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3461,6 +3467,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3701,6 +3713,55 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 bytes length MAC addresses
+     and stores it in 8 byte length format.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer <type>macaddr</> type for the list of input types that
+     are supported in 6 bytes length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b214218..d3310f7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9225,6 +9225,50 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..3a3903b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,5 +1,6 @@
 /*
  *	PostgreSQL type definitions for MAC addresses.
+ *	Supports only 6-byte MAC addresses
  *
  *	src/backend/utils/adt/mac.c
  */
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..589e708
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,437 @@
+/*
+ *	PostgreSQL type definitions for MAC addresses.
+ *	Support both EUI-48 and EUI-64 formats (6 and 8 byte address lengths).
+ *
+ *	The following code is written with the assumption of OUI field
+ *	size as 24 bits
+ *
+ *	src/backend/utils/adt/mac8.c
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	char	   *str = PG_GETARG_CSTRING(0);
+	macaddr8   *result;
+	int			a,
+				b,
+				c,
+				d,
+				e,
+				f,
+				g,
+				h;
+	char		junk[2];
+	int			count;
+
+	/* %1s matches iff there is trailing non-whitespace garbage */
+	count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
+				   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+	if (count != 6)
+		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
+					   &a, &b, &c, &f, &g, &h, junk);
+
+	if (count == 6)
+	{
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else
+	{
+		/* May be a 8-byte MAC address */
+		count = sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x%1s",
+					   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%x-%x-%x-%x-%x-%x-%x-%x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x.%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x-%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x:%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+			count = sscanf(str, "%2x%2x%2x%2x%2x%2x%2x%2x%1s",
+						   &a, &b, &c, &d, &e, &f, &g, &h, junk);
+		if (count != 8)
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+		}
+	}
+
+	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+		(e < 0) || (e > 255) || (f < 0) || (f > 255) ||
+		(g < 0) || (g > 255) || (h < 0) || (h > 255))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+		  errmsg("invalid octet value in \"macaddr8\" value: \"%s\"", str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*----------------------------------------------------------
+ *	Conversion operators.
+ *---------------------------------------------------------*/
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			  errhint("The addresses that comes with FF and FE as values in "
+					  "3rd and 4th bytes starts from left, for example: "
+					  "XX-XX-XX-FF-FE-XX-XX-XX are eligible to convert from "
+					  "macaddr8 to macaddr datatype")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..2459adc 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= ((double) 256) * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fa32e9e..c29ff16 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3799,6 +3799,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..546527a 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops	PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops	PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 05652e8..e681ebb 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,31 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4052,6 +4079,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 6e4c65e..9f61238 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 774
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..3f60280 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)	((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)	PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..b6ac9ef
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,251 @@
+--
+-- macaddr8
+--
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0800:2b01:0203"
+LINE 1: INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+                                             ^
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(19 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(19 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(19 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(19 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(19 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index edeb2d6..f4ce199 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 27a46d7..e139d7b 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..48b542d
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,60 @@
+--
+-- macaddr8
+--
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203'); -- invalid
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
#61Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: Haribabu Kommi (#60)
[REVIEW] macaddr 64 bit (EUI-64) datatype support

Hello,

I've reviewed the patch[1]/messages/by-id/CAJrrPGeT8zrGPMcRVk_wRvYD-ETcgUz6WRrc2C=iNubMRkrMxw@mail.gmail.com.

Result of testing:

make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

The patch introduce a new type macaddr8 for EUI-64 addresses[2]http://standards.ieee.org/develop/regauth/tut/eui64.pdf -- Best regards, Vitaly Burovoy
(assuming OUI field is 24 bits wide) with EUI-48 (existing "macaddr"
type) interoperability.
It is a mostly copy-pasted macaddr implementation with necessary
changes for increased range.
Consensus was reached on such implementation in the current thread before.

There are two patch files for convenient reviewing: base macaddr8
implementation and its supporting in btree-gin and btree-gist indexes.

The patch:
* cleanly applies to the current master
(6af8b89adba16f97bee0d3b01256861e10d0e4f1);
* passes tests;
* looks fine, follows the PostgreSQL style guide;
* has documentation changes;
* has tests.

All notes and requirements were took into account and the patch was
changed according to them.
I have no suggestions on improving it.

The new status of this patch is: Ready for Committer

P.S.:
1. The doc and error/hint messages should be proof-read by a native speaker.
2. A committer should bump catversion. It is not bumped in the patch
because it is unclear when it is committed.

[1]: /messages/by-id/CAJrrPGeT8zrGPMcRVk_wRvYD-ETcgUz6WRrc2C=iNubMRkrMxw@mail.gmail.com
[2]: http://standards.ieee.org/develop/regauth/tut/eui64.pdf -- Best regards, Vitaly Burovoy
--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#62Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Vitaly Burovoy (#61)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On Wed, Feb 1, 2017 at 12:57 AM, Vitaly Burovoy
<vitaly.burovoy@gmail.com> wrote:

Hello,

I've reviewed the patch[1].

Noting to add from my side as well.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#63Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Vitaly Burovoy (#61)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <vitaly.burovoy@gmail.com>
wrote:

Hello,

I've reviewed the patch[1].

Result of testing:

make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

The patch introduce a new type macaddr8 for EUI-64 addresses[2]
(assuming OUI field is 24 bits wide) with EUI-48 (existing "macaddr"
type) interoperability.
It is a mostly copy-pasted macaddr implementation with necessary
changes for increased range.
Consensus was reached on such implementation in the current thread before.

There are two patch files for convenient reviewing: base macaddr8
implementation and its supporting in btree-gin and btree-gist indexes.

The patch:
* cleanly applies to the current master
(6af8b89adba16f97bee0d3b01256861e10d0e4f1);
* passes tests;
* looks fine, follows the PostgreSQL style guide;
* has documentation changes;
* has tests.

All notes and requirements were took into account and the patch was
changed according to them.
I have no suggestions on improving it.

The new status of this patch is: Ready for Committer

Thanks for the review.

Regards,
Hari Babu
Fujitsu Australia

#64Stephen Frost
sfrost@snowman.net
In reply to: Haribabu Kommi (#63)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Hari Babu,

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <vitaly.burovoy@gmail.com> wrote:

The new status of this patch is: Ready for Committer

Thanks for the review.

I've started taking a look at this with an eye towards committing it
soon.

Thanks!

Stephen

#65Stephen Frost
sfrost@snowman.net
In reply to: Stephen Frost (#64)
1 attachment(s)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Greetings,

* Stephen Frost (sfrost@snowman.net) wrote:

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <vitaly.burovoy@gmail.com> wrote:

The new status of this patch is: Ready for Committer

Thanks for the review.

I've started taking a look at this with an eye towards committing it
soon.

I've spent a good bit of time going over this, possibly even more than
it was worth, but hopefully we'll see people making use of this data
type with PG10 and as more IPv6 deployment happens.

Of particular note, I rewrote macaddr8_in to not use sscanf().
sscanf(), at least on my system, would accept negative values even for
'%2x', leading to slightly odd errors with certain inputs, including
with our existing macaddr type:

=# select '00-203040506'::macaddr;
ERROR: invalid octet value in "macaddr" value: "00-203040506"
LINE 1: select '00-203040506'::macaddr;

With my rewrite, the macaddr8 type will throw a clearer (in my view, at
least) error:

=# select '00-203040506'::macaddr8;
ERROR: invalid input syntax for type macaddr8: "00-203040506"
LINE 1: select '00-203040506'::macaddr8;

One other point is that the previously disallowed format with just two
colons ('0800:2b01:0203') is now allowed. Given that both the two dot
format ('0800.2b01.0203') and the two dash format ('0800-2b01-0203')
were accepted, this seemed alright to me. Is there really a good reason
to disallow the two colon format?

I didn't change how macaddr works as it doesn't appear to produce any
outright incorrect behavior as-is (just slightly odd error messages) and
some users might be expecting the current errors. I don't hold that
position very strongly, however, and I have little doubt that the new
macaddr8_in() is faster than using sscanf(), so that might be reason to
consider rewriting macaddr_in in a similar fashion (or having a generic
set of functions to handle both). I considered using the functions we
already use for bytea, but they don't quite match up to the expectations
for MAC addresses (in particular, we shouldn't accept random whitespace
in the middle of a MAC address). Perhaps we could modify those
functions to be parameterized in a way to support how a MAC address
should look, but it's not all that much code to be reason enough to put
a lot of effort towards that, in my view at least. This also reduces
the risk that bugs get introduced which break existing behavior too.

I also thought about what we expect the usage of macaddr8 to be and
realized that we should really have a function to help go from EUI-48 to
the IPv6 Modified EUI-64 format, since users will almost certainly want
to do exactly that. As such, I added a macaddr8_set7bit() function
which will perform the EUI-64 -> Modified EUI-64 change (which is just
setting the 7th bit) and added associated documentation and reasoning
for why that function exists.

In any case, it would be great to get some additional review of this, in
particular of my modifications to macaddr8_in() and if anyone has any
thoughts regarding the added macaddr8_set7bit() function. I'm going to
take a break from it for a couple days to see if there's any additional
comments and then go over it again myself.

Barring issues, I'll commit the attached later this week.

Thanks!

Stephen

Attachments:

mac_eui64_support_v11.patchtext/x-diff; charset=us-asciiDownload
From 239affc0e5b09964029f075c5370556c56de005d Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 9 Mar 2017 17:47:28 -0500
Subject: [PATCH] Add support for EUI-64 MAC addresses as macaddr8

This adds in support for EUI-64 MAC addresses by adding a new data type
called 'macaddr8' (using our usual convention of indicating the number
of bytes stored).

This was largely a copy-and-paste from the macaddr data type, with
appropriate adjustments for having 8 bytes instead of 6 and adding
support for converting a provided EUI-48 (6 byte format) to the EUI-64
format.  Conversion from EUI-48 to EUI-64 adds FFFE as the 4th and 5th
bytes but does not perform the IPv6 modified EUI-64 action of flipping
the 7th bit, but we add a function to perform that specific action for
the user as it may be commonly done by users who wish to calculate their
IPv6 address based on their network prefix and 48-bit MAC address.

Author: Haribabu Kommi, with a good bit of rework of macaddr8_in by me.
Reviewed by: Vitaly Burovoy, Kuntal Ghosh

Discussion: https://postgr.es/m/CAJrrPGcUi8ZH+KkK+=TctNQ+EfkeCEHtMU_yo1mvX8hsk_ghNQ@mail.gmail.com
---
 contrib/btree_gin/Makefile                  |   4 +-
 contrib/btree_gin/btree_gin--1.0--1.1.sql   |  35 ++
 contrib/btree_gin/btree_gin.c               |  10 +
 contrib/btree_gin/btree_gin.control         |   2 +-
 contrib/btree_gin/expected/macaddr8.out     |  51 +++
 contrib/btree_gin/sql/macaddr8.sql          |  22 ++
 contrib/btree_gist/Makefile                 |  11 +-
 contrib/btree_gist/btree_gist--1.3--1.4.sql |  64 ++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_gist.h             |   1 +
 contrib/btree_gist/btree_macaddr8.c         | 200 ++++++++++
 contrib/btree_gist/expected/macaddr8.out    |  89 +++++
 contrib/btree_gist/sql/macaddr8.sql         |  37 ++
 doc/src/sgml/brin.sgml                      |  11 +
 doc/src/sgml/btree-gin.sgml                 |   3 +-
 doc/src/sgml/btree-gist.sgml                |   4 +-
 doc/src/sgml/datatype.sgml                  |  83 +++++
 doc/src/sgml/func.sgml                      |  56 +++
 src/backend/utils/adt/Makefile              |   2 +-
 src/backend/utils/adt/mac.c                 |  13 +-
 src/backend/utils/adt/mac8.c                | 560 ++++++++++++++++++++++++++++
 src/backend/utils/adt/network.c             |  10 +
 src/backend/utils/adt/selfuncs.c            |   1 +
 src/include/catalog/pg_amop.h               |  18 +
 src/include/catalog/pg_amproc.h             |   7 +
 src/include/catalog/pg_cast.h               |   6 +
 src/include/catalog/pg_opclass.h            |   3 +
 src/include/catalog/pg_operator.h           |  23 +-
 src/include/catalog/pg_opfamily.h           |   3 +
 src/include/catalog/pg_proc.h               |  37 +-
 src/include/catalog/pg_type.h               |   4 +
 src/include/utils/inet.h                    |  22 ++
 src/test/regress/expected/macaddr8.out      | 355 ++++++++++++++++++
 src/test/regress/expected/opr_sanity.out    |   6 +
 src/test/regress/parallel_schedule          |   2 +-
 src/test/regress/serial_schedule            |   1 +
 src/test/regress/sql/macaddr8.sql           |  89 +++++
 37 files changed, 1827 insertions(+), 20 deletions(-)
 create mode 100644 contrib/btree_gin/btree_gin--1.0--1.1.sql
 create mode 100644 contrib/btree_gin/expected/macaddr8.out
 create mode 100644 contrib/btree_gin/sql/macaddr8.sql
 create mode 100644 contrib/btree_gist/btree_gist--1.3--1.4.sql
 create mode 100644 contrib/btree_gist/btree_macaddr8.c
 create mode 100644 contrib/btree_gist/expected/macaddr8.out
 create mode 100644 contrib/btree_gist/sql/macaddr8.sql
 create mode 100644 src/backend/utils/adt/mac8.c
 create mode 100644 src/test/regress/expected/macaddr8.out
 create mode 100644 src/test/regress/sql/macaddr8.sql

diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..dd81d27
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8, macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..725456e 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8   *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d..d96436e 100644
--- a/contrib/btree_gin/btree_gin.control
+++ b/contrib/btree_gin/btree_gin.control
@@ -1,5 +1,5 @@
 # btree_gin extension
 comment = 'support for indexing common datatypes in GIN'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/btree_gin'
 relocatable = true
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..c70f178 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+        btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+        bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..c463bca
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8	lower;
+	macaddr8	upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY    *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY    *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 * m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8   *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY    *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY    *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY    *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 6448b18..5bf11dc 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3561030..4db0491 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3428,6 +3434,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3668,6 +3680,77 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 byte length MAC addresses
+     and stores them in 8 byte length format.  MAC addresses given
+     in 6 byte format will be stored in 8 byte length format with the
+     3rd and 4th bytes set to FF and FE, respectively.
+
+     Note that IPv6 uses a modified EUI-64 format where the 7th bit
+     should be set to one after the conversion from EUI-48.  The
+     function <function>macaddr8_set7bit</> is provided to make this
+     change.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+
+     To convert a traditional 48 bit MAC address in EUI-48 format to
+     modified EUI-64 format to be included as the host portion of an
+     IPv6 address, use <function>macaddr8_set7bit</> as shown:
+
+<programlisting>
+SELECT macaddr8_set7bit('08:00:2b:01:02:03');
+<computeroutput>
+    macaddr8_set7bit     
+-------------------------
+ 0a:00:2b:ff:fe:01:02:03
+(1 row)
+</computeroutput>
+</programlisting>
+
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer to the <type>macaddr</> type for the list of input types that
+     are supported in 6-byte length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 583b3b2..a521912 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9228,6 +9228,62 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>macaddr8_set7bit</primary>
+         </indexterm>
+         <literal><function>macaddr8_set7bit(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set 7th bit to one, also known as modified EUI-64, for inclusion in an IPv6 address</entry>
+        <entry><literal>macaddr8_set7bit(macaddr8 '00:34:56:ab:cd:ef')</literal></entry>
+        <entry><literal>02:34:56:ff:fe:ab:cd:ef</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..cd0e34b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,7 +1,14 @@
-/*
- *	PostgreSQL type definitions for MAC addresses.
+/*-------------------------------------------------------------------------
+ *
+ * mac.c
+ *    PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
+ *
+ * Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *        src/backend/utils/adt/mac.c
  *
- *	src/backend/utils/adt/mac.c
+ *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..81110e5
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,560 @@
+/*-------------------------------------------------------------------------
+ *
+ * mac8.c
+ *	  PostgreSQL type definitions for 8 byte (EUI-64) MAC addresses.
+ *
+ * EUI-48 (6 byte) MAC addresses are accepted as input and are stored in
+ * EUI-64 format, with the 3rd and 4th bytes set to FF and FE, respectively.
+ *
+ * Output is always in 8 byte (EUI-64) format.
+ *
+ * The following code is written with the assumption that the OUI field
+ * size is 24 bits.
+ *
+ * Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		  src/backend/utils/adt/mac8.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+static unsigned char hex2_to_uchar(const char *str, int offset);
+
+static const int hexlookup[128] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static inline unsigned char
+hex2_to_uchar(const char *str, int offset)
+{
+	unsigned char ret = 0;
+	int			lookup;
+	const char *ptr = str + offset;
+
+	/* Handle the first character */
+	if (*ptr < 0 || *ptr >= 127)
+		goto invalid_input;
+
+	lookup = hexlookup[(unsigned char) *ptr];
+	if (lookup < 0 || lookup > 15)
+		goto invalid_input;
+
+	ret = lookup << 4;
+
+	/* Move to the second character */
+	ptr++;
+
+	if (*ptr < 0 || *ptr > 127)
+		goto invalid_input;
+
+	lookup = hexlookup[(unsigned char) *ptr];
+	if (lookup < 0 || lookup > 15)
+		goto invalid_input;
+
+	ret += lookup;
+
+	return ret;
+
+invalid_input:
+	ereport(ERROR,
+			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					str)));
+
+	/* We do not actually reach here */
+	return 0;
+}
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	const char *str = PG_GETARG_CSTRING(0);
+	const char *ptr = str;
+	macaddr8   *result;
+	unsigned char a = 0,
+				b = 0,
+				c = 0,
+				d = 0,
+				e = 0,
+				f = 0,
+				g = 0,
+				h = 0;
+	int			count = 0;
+	char		spacer = '\0';
+
+	/* skip leading spaces */
+	while (*ptr && isspace((unsigned char) *ptr))
+		ptr++;
+
+	/* digits must always come in pairs */
+	while (*ptr && *(ptr + 1))
+	{
+		/*
+		 * Attempt to decode each byte, which must be 2 hex digits in a row.
+		 * If either digit is not hex, hex2_to_uchar will throw ereport() for
+		 * us.  Either 6 or 8 byte MAC addresses are supported.
+		 */
+
+		/* Attempt to collect a byte */
+		count++;
+
+		switch (count)
+		{
+			case 1:
+				a = hex2_to_uchar(str, ptr - str);
+				break;
+			case 2:
+				b = hex2_to_uchar(str, ptr - str);
+				break;
+			case 3:
+				c = hex2_to_uchar(str, ptr - str);
+				break;
+			case 4:
+				d = hex2_to_uchar(str, ptr - str);
+				break;
+			case 5:
+				e = hex2_to_uchar(str, ptr - str);
+				break;
+			case 6:
+				f = hex2_to_uchar(str, ptr - str);
+				break;
+			case 7:
+				g = hex2_to_uchar(str, ptr - str);
+				break;
+			case 8:
+				h = hex2_to_uchar(str, ptr - str);
+				break;
+			default:
+				/* must be trailing garbage... */
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					   str)));
+		}
+
+		/* Move forward to where the next byte should be */
+		ptr += 2;
+
+		/* Check for a spacer, these are valid, anything else is not */
+		if (*ptr == ':' || *ptr == '-' || *ptr == '.')
+		{
+			/* remember the spacer used, if it changes then it isn't valid */
+			if (spacer == '\0')
+				spacer = *ptr;
+
+			/* Have to use the same spacer throughout */
+			else if (spacer != *ptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					   str)));
+
+			/* move past the spacer */
+			ptr++;
+		}
+
+		/* allow trailing whitespace after if we have 6 or 8 bytes */
+		if (count == 6 || count == 8)
+		{
+			if (isspace((unsigned char) *ptr))
+			{
+				while (*++ptr && isspace((unsigned char) *ptr));
+
+				/* If we found a space and then non-space, it's invalid */
+				if (*ptr)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+									str)));
+			}
+		}
+	}
+
+	/* Convert a 6 byte MAC address to macaddr8 */
+	if (count == 6)
+	{
+		h = f;
+		g = e;
+		f = d;
+
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else if (count != 8)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Set 7th bit for modified EUI-64 as used in IPv6.
+ */
+Datum
+macaddr8_set7bit(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a | 0x02;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->d;
+	result->e = addr->e;
+	result->f = addr->f;
+	result->g = addr->g;
+	result->h = addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*----------------------------------------------------------
+ *	Conversion operators.
+ *---------------------------------------------------------*/
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			   errhint("Only addresses that have FF and FE as values in the "
+					   "3rd and 4th bytes, from the left, for example: "
+					 "XX-XX-XX-FF-FE-XX-XX-XX, are eligible to be converted "
+					   "from macaddr8 to macaddr.")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..2459adc 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= ((double) 256) * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index a04fd7b..4b4c37b 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3800,6 +3800,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..546527a 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops	PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops	PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ec4aedb..3d5d866 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,33 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+DATA(insert OID = 4125 (  macaddr8_set7bit	PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_set7bit _null_ _null_ _null_ ));
+DESCR("set 7th bit in macaddr8");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4056,6 +4085,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 6e4c65e..9f61238 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 774
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..3f60280 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)	((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)	PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..bd83b68
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,355 @@
+--
+-- macaddr8
+--
+-- test various cases of valid and invalid input
+-- valid
+SELECT '08:00:2b:01:02:03     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '    08:00:2b:01:02:03     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '    08:00:2b:01:02:03'::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '08:00:2b:01:02:03:04:05     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '    08:00:2b:01:02:03:04:05     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '    08:00:2b:01:02:03:04:05'::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '123    08:00:2b:01:02:03'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "123    08:00:2b:01:02:03"
+LINE 1: SELECT '123    08:00:2b:01:02:03'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03  123'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03  123"
+LINE 1: SELECT '08:00:2b:01:02:03  123'::macaddr8;
+               ^
+SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "123    08:00:2b:01:02:03:04:05"
+LINE 1: SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:05  123"
+LINE 1: SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:05:06:07"
+LINE 1: SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8;
+               ^
+SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08-00-2b-01-02-03-04-05-06-07"
+LINE 1: SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8;
+               ^
+SELECT '08002b:01020304050607'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b:01020304050607"
+LINE 1: SELECT '08002b:01020304050607'::macaddr8;
+               ^
+SELECT '08002b01020304050607'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b01020304050607"
+LINE 1: SELECT '08002b01020304050607'::macaddr8;
+               ^
+SELECT '0z002b0102030405'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0z002b0102030405"
+LINE 1: SELECT '0z002b0102030405'::macaddr8;
+               ^
+SELECT '08002b010203xyza'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b010203xyza"
+LINE 1: SELECT '08002b010203xyza'::macaddr8;
+               ^
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00-2b:01:02:03:04:05"
+LINE 1: SELECT '08:00-2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00-2b:01:02:03:04:05"
+LINE 1: SELECT '08:00-2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01.02:03:04:05"
+LINE 1: SELECT '08:00:2b:01.02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01.02:03:04:05"
+LINE 1: SELECT '08:00:2b:01.02:03:04:05'::macaddr8;
+               ^
+-- test converting a MAC address to modified EUI-64 for inclusion
+-- in an ipv6 address
+SELECT macaddr8_set7bit('00:08:2b:01:02:03'::macaddr8);
+    macaddr8_set7bit     
+-------------------------
+ 02:08:2b:ff:fe:01:02:03
+(1 row)
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data ORDER BY 1;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+  8 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(20 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  8 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(20 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(20 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(20 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(20 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 9f38349..ea7b5b4 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 2987b24..cf48ea7 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..57a227c
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,89 @@
+--
+-- macaddr8
+--
+
+-- test various cases of valid and invalid input
+-- valid
+SELECT '08:00:2b:01:02:03     '::macaddr8;
+SELECT '    08:00:2b:01:02:03     '::macaddr8;
+SELECT '    08:00:2b:01:02:03'::macaddr8;
+SELECT '08:00:2b:01:02:03:04:05     '::macaddr8;
+SELECT '    08:00:2b:01:02:03:04:05     '::macaddr8;
+SELECT '    08:00:2b:01:02:03:04:05'::macaddr8;
+
+SELECT '123    08:00:2b:01:02:03'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03  123'::macaddr8; -- invalid
+SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8; -- invalid
+SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8; -- invalid
+SELECT '08002b:01020304050607'::macaddr8; -- invalid
+SELECT '08002b01020304050607'::macaddr8; -- invalid
+SELECT '0z002b0102030405'::macaddr8; -- invalid
+SELECT '08002b010203xyza'::macaddr8; -- invalid
+
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+
+-- test converting a MAC address to modified EUI-64 for inclusion
+-- in an ipv6 address
+SELECT macaddr8_set7bit('00:08:2b:01:02:03'::macaddr8);
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data ORDER BY 1;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
-- 
2.7.4

#66Stephen Frost
sfrost@snowman.net
In reply to: Stephen Frost (#65)
1 attachment(s)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Greetings,

* Stephen Frost (sfrost@snowman.net) wrote:

* Stephen Frost (sfrost@snowman.net) wrote:

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <vitaly.burovoy@gmail.com> wrote:

The new status of this patch is: Ready for Committer

Thanks for the review.

I've started taking a look at this with an eye towards committing it
soon.

I've spent a good bit of time going over this, possibly even more than
it was worth, but hopefully we'll see people making use of this data
type with PG10 and as more IPv6 deployment happens.

And, naturally, re-reading the email as it hit the list made me realize
that the documentation/error-message incorrectly said "3rd and 4th"
bytes were being set to FF and FE, when it's actually the 4th and 5th
byte. The code was correct, just the documentation and the error
message had the wrong numbers. The commit message is also correct.

As a reminder to myself, this will also need a catversion bump when it
gets committed, of course.

Updated patch attached.

Thanks!

Stephen

Attachments:

mac_eui64_support_v12.patchtext/x-diff; charset=us-asciiDownload
From 5b470010cacdc32bec521b1d57ad9f60c7bd638a Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 9 Mar 2017 17:47:28 -0500
Subject: [PATCH] Add support for EUI-64 MAC addresses as macaddr8

This adds in support for EUI-64 MAC addresses by adding a new data type
called 'macaddr8' (using our usual convention of indicating the number
of bytes stored).

This was largely a copy-and-paste from the macaddr data type, with
appropriate adjustments for having 8 bytes instead of 6 and adding
support for converting a provided EUI-48 (6 byte format) to the EUI-64
format.  Conversion from EUI-48 to EUI-64 inserts FFFE as the 4th and
5th bytes but does not perform the IPv6 modified EUI-64 action of
flipping the 7th bit, but we add a function to perform that specific
action for the user as it may be commonly done by users who wish to
calculate their IPv6 address based on their network prefix and 48-bit
MAC address.

Author: Haribabu Kommi, with a good bit of rework of macaddr8_in by me.
Reviewed by: Vitaly Burovoy, Kuntal Ghosh

Discussion: https://postgr.es/m/CAJrrPGcUi8ZH+KkK+=TctNQ+EfkeCEHtMU_yo1mvX8hsk_ghNQ@mail.gmail.com
---
 contrib/btree_gin/Makefile                  |   4 +-
 contrib/btree_gin/btree_gin--1.0--1.1.sql   |  35 ++
 contrib/btree_gin/btree_gin.c               |  10 +
 contrib/btree_gin/btree_gin.control         |   2 +-
 contrib/btree_gin/expected/macaddr8.out     |  51 +++
 contrib/btree_gin/sql/macaddr8.sql          |  22 ++
 contrib/btree_gist/Makefile                 |  11 +-
 contrib/btree_gist/btree_gist--1.3--1.4.sql |  64 ++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_gist.h             |   1 +
 contrib/btree_gist/btree_macaddr8.c         | 200 ++++++++++
 contrib/btree_gist/expected/macaddr8.out    |  89 +++++
 contrib/btree_gist/sql/macaddr8.sql         |  37 ++
 doc/src/sgml/brin.sgml                      |  11 +
 doc/src/sgml/btree-gin.sgml                 |   3 +-
 doc/src/sgml/btree-gist.sgml                |   4 +-
 doc/src/sgml/datatype.sgml                  |  83 +++++
 doc/src/sgml/func.sgml                      |  56 +++
 src/backend/utils/adt/Makefile              |   2 +-
 src/backend/utils/adt/mac.c                 |  13 +-
 src/backend/utils/adt/mac8.c                | 560 ++++++++++++++++++++++++++++
 src/backend/utils/adt/network.c             |  10 +
 src/backend/utils/adt/selfuncs.c            |   1 +
 src/include/catalog/pg_amop.h               |  18 +
 src/include/catalog/pg_amproc.h             |   7 +
 src/include/catalog/pg_cast.h               |   6 +
 src/include/catalog/pg_opclass.h            |   3 +
 src/include/catalog/pg_operator.h           |  23 +-
 src/include/catalog/pg_opfamily.h           |   3 +
 src/include/catalog/pg_proc.h               |  37 +-
 src/include/catalog/pg_type.h               |   4 +
 src/include/utils/inet.h                    |  22 ++
 src/test/regress/expected/macaddr8.out      | 355 ++++++++++++++++++
 src/test/regress/expected/opr_sanity.out    |   6 +
 src/test/regress/parallel_schedule          |   2 +-
 src/test/regress/serial_schedule            |   1 +
 src/test/regress/sql/macaddr8.sql           |  89 +++++
 37 files changed, 1827 insertions(+), 20 deletions(-)
 create mode 100644 contrib/btree_gin/btree_gin--1.0--1.1.sql
 create mode 100644 contrib/btree_gin/expected/macaddr8.out
 create mode 100644 contrib/btree_gin/sql/macaddr8.sql
 create mode 100644 contrib/btree_gist/btree_gist--1.3--1.4.sql
 create mode 100644 contrib/btree_gist/btree_macaddr8.c
 create mode 100644 contrib/btree_gist/expected/macaddr8.out
 create mode 100644 contrib/btree_gist/sql/macaddr8.sql
 create mode 100644 src/backend/utils/adt/mac8.c
 create mode 100644 src/test/regress/expected/macaddr8.out
 create mode 100644 src/test/regress/sql/macaddr8.sql

diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091..f22e4af 100644
--- a/contrib/btree_gin/Makefile
+++ b/contrib/btree_gin/Makefile
@@ -4,12 +4,12 @@ MODULE_big = btree_gin
 OBJS = btree_gin.o $(WIN32RES)
 
 EXTENSION = btree_gin
-DATA = btree_gin--1.0.sql btree_gin--unpackaged--1.0.sql
+DATA = btree_gin--1.0.sql btree_gin--1.0--1.1.sql btree_gin--unpackaged--1.0.sql
 PGFILEDESC = "btree_gin - B-tree equivalent GIN operator classes"
 
 REGRESS = install_btree_gin int2 int4 int8 float4 float8 money oid \
 	timestamp timestamptz time timetz date interval \
-	macaddr inet cidr text varchar char bytea bit varbit \
+	macaddr macaddr8 inet cidr text varchar char bytea bit varbit \
 	numeric
 
 ifdef USE_PGXS
diff --git a/contrib/btree_gin/btree_gin--1.0--1.1.sql b/contrib/btree_gin/btree_gin--1.0--1.1.sql
new file mode 100644
index 0000000..dd81d27
--- /dev/null
+++ b/contrib/btree_gin/btree_gin--1.0--1.1.sql
@@ -0,0 +1,35 @@
+/* contrib/btree_gin/btree_gin--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gin UPDATE TO '1.1'" to load this file. \quit
+
+-- macaddr8 datatype support new in 10.0.
+CREATE FUNCTION gin_extract_value_macaddr8(macaddr8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR CLASS macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gin
+AS
+    OPERATOR        1       <,
+    OPERATOR        2       <=,
+    OPERATOR        3       =,
+    OPERATOR        4       >=,
+    OPERATOR        5       >,
+    FUNCTION        1       macaddr8_cmp(macaddr8, macaddr8),
+    FUNCTION        2       gin_extract_value_macaddr8(macaddr8, internal),
+    FUNCTION        3       gin_extract_query_macaddr8(macaddr8, internal, int2, internal, internal),
+    FUNCTION        4       gin_btree_consistent(internal, int2, anyelement, int4, internal, internal),
+    FUNCTION        5       gin_compare_prefix_macaddr8(macaddr8, macaddr8, int2, internal),
+STORAGE         macaddr8;
diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 030b610..725456e 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -323,6 +323,16 @@ leftmostvalue_macaddr(void)
 GIN_SUPPORT(macaddr, false, leftmostvalue_macaddr, macaddr_cmp)
 
 static Datum
+leftmostvalue_macaddr8(void)
+{
+	macaddr8   *v = palloc0(sizeof(macaddr8));
+
+	return Macaddr8PGetDatum(v);
+}
+
+GIN_SUPPORT(macaddr8, false, leftmostvalue_macaddr8, macaddr8_cmp)
+
+static Datum
 leftmostvalue_inet(void)
 {
 	return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d..d96436e 100644
--- a/contrib/btree_gin/btree_gin.control
+++ b/contrib/btree_gin/btree_gin.control
@@ -1,5 +1,5 @@
 # btree_gin extension
 comment = 'support for indexing common datatypes in GIN'
-default_version = '1.0'
+default_version = '1.1'
 module_pathname = '$libdir/btree_gin'
 relocatable = true
diff --git a/contrib/btree_gin/expected/macaddr8.out b/contrib/btree_gin/expected/macaddr8.out
new file mode 100644
index 0000000..025b0c1
--- /dev/null
+++ b/contrib/btree_gin/expected/macaddr8.out
@@ -0,0 +1,51 @@
+set enable_seqscan=off;
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:03:55:08:01:02
+ 22:00:5c:04:55:08:01:02
+ 22:00:5c:05:55:08:01:02
+ 22:00:5c:08:55:08:01:02
+(4 rows)
+
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+(1 row)
+
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:08:55:08:01:02
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(3 rows)
+
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+            i            
+-------------------------
+ 22:00:5c:09:55:08:01:02
+ 22:00:5c:10:55:08:01:02
+(2 rows)
+
diff --git a/contrib/btree_gin/sql/macaddr8.sql b/contrib/btree_gin/sql/macaddr8.sql
new file mode 100644
index 0000000..86785c3
--- /dev/null
+++ b/contrib/btree_gin/sql/macaddr8.sql
@@ -0,0 +1,22 @@
+set enable_seqscan=off;
+
+CREATE TABLE test_macaddr8 (
+	i macaddr8
+);
+
+INSERT INTO test_macaddr8 VALUES
+	( '22:00:5c:03:55:08:01:02' ),
+	( '22:00:5c:04:55:08:01:02' ),
+	( '22:00:5c:05:55:08:01:02' ),
+	( '22:00:5c:08:55:08:01:02' ),
+	( '22:00:5c:09:55:08:01:02' ),
+	( '22:00:5c:10:55:08:01:02' )
+;
+
+CREATE INDEX idx_macaddr8 ON test_macaddr8 USING gin (i);
+
+SELECT * FROM test_macaddr8 WHERE i<'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i<='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>='22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
+SELECT * FROM test_macaddr8 WHERE i>'22:00:5c:08:55:08:01:02'::macaddr8 ORDER BY i;
diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index d36f517..c70f178 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -5,17 +5,18 @@ MODULE_big = btree_gist
 OBJS =  btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
         btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
         btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
-        btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
-        btree_numeric.o btree_uuid.o $(WIN32RES)
+        btree_macaddr.o btree_macaddr8.o btree_inet.o btree_text.o btree_bytea.o \
+        btree_bit.o btree_numeric.o btree_uuid.o $(WIN32RES)
 
 EXTENSION = btree_gist
 DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
-       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
+       btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
+       btree_gist--1.3--1.4.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
-        time timetz date interval macaddr inet cidr text varchar char bytea \
-        bit varbit numeric uuid not_equal
+        time timetz date interval macaddr macaddr8 inet cidr text varchar char \
+        bytea bit varbit numeric uuid not_equal
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.3--1.4.sql b/contrib/btree_gist/btree_gist--1.3--1.4.sql
new file mode 100644
index 0000000..f77f6c8
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.3--1.4.sql
@@ -0,0 +1,64 @@
+/* contrib/btree_gist/btree_gist--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.4'" to load this file. \quit
+
+-- Add support for indexing macaddr8 columns
+
+-- define the GiST support methods
+CREATE FUNCTION gbt_macad8_consistent(internal,macaddr8,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_union(internal, internal)
+RETURNS gbtreekey16
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_macad8_same(gbtreekey16, gbtreekey16, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_macaddr8_ops
+DEFAULT FOR TYPE macaddr8 USING gist
+AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	gbt_macad8_consistent (internal, macaddr8, int2, oid, internal),
+	FUNCTION	2	gbt_macad8_union (internal, internal),
+	FUNCTION	3	gbt_macad8_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_macad8_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_macad8_picksplit (internal, internal),
+	FUNCTION	7	gbt_macad8_same (gbtreekey16, gbtreekey16, internal),
+	STORAGE		gbtreekey16;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+	OPERATOR	6	<> (macaddr8, macaddr8) ,
+	FUNCTION	9 (macaddr8, macaddr8) gbt_macad8_fetch (internal);
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index ddbf83d..fdf0e6a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,5 +1,5 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 9b3e22c..f759299 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -27,6 +27,7 @@ enum gbtree_type
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
+	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
diff --git a/contrib/btree_gist/btree_macaddr8.c b/contrib/btree_gist/btree_macaddr8.c
new file mode 100644
index 0000000..c463bca
--- /dev/null
+++ b/contrib/btree_gist/btree_macaddr8.c
@@ -0,0 +1,200 @@
+/*
+ * contrib/btree_gist/btree_macaddr8.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+typedef struct
+{
+	macaddr8	lower;
+	macaddr8	upper;
+	/* make struct size = sizeof(gbtreekey16) */
+} mac8KEY;
+
+/*
+** OID ops
+*/
+PG_FUNCTION_INFO_V1(gbt_macad8_compress);
+PG_FUNCTION_INFO_V1(gbt_macad8_fetch);
+PG_FUNCTION_INFO_V1(gbt_macad8_union);
+PG_FUNCTION_INFO_V1(gbt_macad8_picksplit);
+PG_FUNCTION_INFO_V1(gbt_macad8_consistent);
+PG_FUNCTION_INFO_V1(gbt_macad8_penalty);
+PG_FUNCTION_INFO_V1(gbt_macad8_same);
+
+
+static bool
+gbt_macad8gt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_gt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+static bool
+gbt_macad8ge(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_ge, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8eq(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_eq, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8le(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_le, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+static bool
+gbt_macad8lt(const void *a, const void *b)
+{
+	return DatumGetBool(DirectFunctionCall2(macaddr8_lt, PointerGetDatum(a), PointerGetDatum(b)));
+}
+
+
+static int
+gbt_macad8key_cmp(const void *a, const void *b)
+{
+	mac8KEY    *ia = (mac8KEY *) (((const Nsrt *) a)->t);
+	mac8KEY    *ib = (mac8KEY *) (((const Nsrt *) b)->t);
+	int			res;
+
+	res = DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->lower), Macaddr8PGetDatum(&ib->lower)));
+	if (res == 0)
+		return DatumGetInt32(DirectFunctionCall2(macaddr8_cmp, Macaddr8PGetDatum(&ia->upper), Macaddr8PGetDatum(&ib->upper)));
+
+	return res;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_macad8,
+	sizeof(macaddr8),
+	16,							/* sizeof(gbtreekey16) */
+	gbt_macad8gt,
+	gbt_macad8ge,
+	gbt_macad8eq,
+	gbt_macad8le,
+	gbt_macad8lt,
+	gbt_macad8key_cmp,
+	NULL
+};
+
+
+/**************************************************
+ * macaddr ops
+ **************************************************/
+
+
+
+static uint64
+mac8_2_uint64(macaddr8 * m)
+{
+	unsigned char *mi = (unsigned char *) m;
+	uint64		res = 0;
+	int			i;
+
+	for (i = 0; i < 8; i++)
+		res += (((uint64) mi[i]) << ((uint64) ((7 - i) * 8)));
+	return res;
+}
+
+
+
+Datum
+gbt_macad8_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_macad8_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	macaddr8   *query = (macaddr8 *) PG_GETARG_POINTER(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	mac8KEY    *kkk = (mac8KEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(
+				   gbt_num_consistent(&key, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
+		);
+}
+
+
+Datum
+gbt_macad8_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc0(sizeof(mac8KEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(mac8KEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
+}
+
+
+Datum
+gbt_macad8_penalty(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *origentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	mac8KEY    *newentry = (mac8KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+	uint64		iorg[2],
+				inew[2];
+
+	iorg[0] = mac8_2_uint64(&origentry->lower);
+	iorg[1] = mac8_2_uint64(&origentry->upper);
+	inew[0] = mac8_2_uint64(&newentry->lower);
+	inew[1] = mac8_2_uint64(&newentry->upper);
+
+	penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
+
+	PG_RETURN_POINTER(result);
+
+}
+
+Datum
+gbt_macad8_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit(
+									(GistEntryVector *) PG_GETARG_POINTER(0),
+									  (GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo
+										));
+}
+
+Datum
+gbt_macad8_same(PG_FUNCTION_ARGS)
+{
+	mac8KEY    *b1 = (mac8KEY *) PG_GETARG_POINTER(0);
+	mac8KEY    *b2 = (mac8KEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/expected/macaddr8.out b/contrib/btree_gist/expected/macaddr8.out
new file mode 100644
index 0000000..e5ec6a5
--- /dev/null
+++ b/contrib/btree_gist/expected/macaddr8.out
@@ -0,0 +1,89 @@
+-- macaddr check
+CREATE TABLE macaddr8tmp (a macaddr8);
+\copy macaddr8tmp from 'data/macaddr.data'
+SET enable_seqscan=on;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+ count 
+-------
+   540
+(1 row)
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    56
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+    60
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+     4
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   544
+(1 row)
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+ count 
+-------
+   540
+(1 row)
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+                       QUERY PLAN                        
+---------------------------------------------------------
+ Index Only Scan using macaddr8idx on macaddr8tmp
+   Index Cond: (a < '02:03:04:ff:fe:05:06:07'::macaddr8)
+(2 rows)
+
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+            a            
+-------------------------
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:02:37:ff:fe:05:4f:36
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+ 01:43:b5:ff:fe:79:eb:0f
+(8 rows)
+
diff --git a/contrib/btree_gist/sql/macaddr8.sql b/contrib/btree_gist/sql/macaddr8.sql
new file mode 100644
index 0000000..61e7d7a
--- /dev/null
+++ b/contrib/btree_gist/sql/macaddr8.sql
@@ -0,0 +1,37 @@
+-- macaddr check
+
+CREATE TABLE macaddr8tmp (a macaddr8);
+
+\copy macaddr8tmp from 'data/macaddr.data'
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d';
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d';
+
+CREATE INDEX macaddr8idx ON macaddr8tmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <  '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a <= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a  = '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >= '22:00:5c:e5:9b:0d'::macaddr8;
+
+SELECT count(*) FROM macaddr8tmp WHERE a >  '22:00:5c:e5:9b:0d'::macaddr8;
+
+-- Test index-only scans
+SET enable_bitmapscan=off;
+EXPLAIN (COSTS OFF)
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
+SELECT * FROM macaddr8tmp WHERE a < '02:03:04:05:06:07'::macaddr8;
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 6448b18..5bf11dc 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -282,6 +282,17 @@
      </entry>
     </row>
     <row>
+     <entry><literal>macaddr8_minmax_ops</literal></entry>
+     <entry><type>macaddr8</type></entry>
+     <entry>
+      <literal>&lt;</literal>
+      <literal>&lt;=</literal>
+      <literal>=</literal>
+      <literal>&gt;=</literal>
+      <literal>&gt;</literal>
+     </entry>
+    </row>
+    <row>
      <entry><literal>name_minmax_ops</literal></entry>
      <entry><type>name</type></entry>
      <entry>
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db..0de8eb5 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>"char"</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, and <type>cidr</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  and <type>cidr</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647c..cfdd5be 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
   <type>time without time zone</>, <type>date</>, <type>interval</>,
   <type>oid</>, <type>money</>, <type>char</>,
   <type>varchar</>, <type>text</>, <type>bytea</>, <type>bit</>,
-  <type>varbit</>, <type>macaddr</>, <type>inet</>, <type>cidr</>,
-  and <type>uuid</>.
+  <type>varbit</>, <type>macaddr</>, <type>macaddr8</>, <type>inet</>,
+  <type>cidr</> and <type>uuid</>.
  </para>
 
  <para>
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 3561030..f4a898f 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -167,6 +167,12 @@
       </row>
 
       <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
+      <row>
        <entry><type>money</type></entry>
        <entry></entry>
        <entry>currency amount</entry>
@@ -3428,6 +3434,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
         <entry>MAC addresses</entry>
        </row>
 
+       <row>
+        <entry><type>macaddr8</type></entry>
+        <entry>8 bytes</entry>
+        <entry>MAC addresses (EUI-64 format)</entry>
+       </row>
+
       </tbody>
      </tgroup>
     </table>
@@ -3668,6 +3680,77 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
     </para>
    </sect2>
 
+   <sect2 id="datatype-macaddr8">
+    <title><type>macaddr8</type></title>
+
+    <indexterm>
+     <primary>macaddr8 (data type)</primary>
+    </indexterm>
+
+    <indexterm>
+     <primary>MAC address (EUI-64 format)</primary>
+     <see>macaddr</see>
+    </indexterm>
+
+    <para>
+     The <type>macaddr8</> type stores MAC addresses in EUI-64
+     format, known for example from Ethernet card hardware addresses
+     (although MAC addresses are used for other purposes as well).
+     This type can accept both 6 and 8 byte length MAC addresses
+     and stores them in 8 byte length format.  MAC addresses given
+     in 6 byte format will be stored in 8 byte length format with the
+     4rd and 5th bytes set to FF and FE, respectively.
+
+     Note that IPv6 uses a modified EUI-64 format where the 7th bit
+     should be set to one after the conversion from EUI-48.  The
+     function <function>macaddr8_set7bit</> is provided to make this
+     change.
+
+     Input is accepted in the following formats:
+
+     <simplelist>
+      <member><literal>'08:00:2b:01:02:03:04:05'</></member>
+      <member><literal>'08-00-2b-01-02-03-04-05'</></member>
+      <member><literal>'08002b:0102030405'</></member>
+      <member><literal>'08002b-0102030405'</></member>
+      <member><literal>'0800.2b01.0203.0405'</></member>
+      <member><literal>'0800-2b01-0203-0405'</></member>
+      <member><literal>'08002b01:02030405'</></member>
+      <member><literal>'08002b0102030405'</></member>
+     </simplelist>
+
+     These examples would all specify the same address.  Upper and
+     lower case is accepted for the digits
+     <literal>a</> through <literal>f</>.  Output is always in the
+     first of the forms shown.
+
+     To convert a traditional 48 bit MAC address in EUI-48 format to
+     modified EUI-64 format to be included as the host portion of an
+     IPv6 address, use <function>macaddr8_set7bit</> as shown:
+
+<programlisting>
+SELECT macaddr8_set7bit('08:00:2b:01:02:03');
+<computeroutput>
+    macaddr8_set7bit     
+-------------------------
+ 0a:00:2b:ff:fe:01:02:03
+(1 row)
+</computeroutput>
+</programlisting>
+
+    </para>
+
+    <para>
+     The last six input formats that are mentioned above are not part
+     of any standard.
+    </para>
+
+    <para>
+     Refer to the <type>macaddr</> type for the list of input types that
+     are supported in 6-byte length format.
+    </para>
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 583b3b2..a521912 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9228,6 +9228,62 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     for NOT, AND and OR.
    </para>
 
+   <para>
+   <xref linkend="macaddr8-functions-table"> shows the functions
+   available for use with the <type>macaddr8</type> type.  The function
+   <literal><function>trunc(<type>macaddr8</type>)</function></literal> returns a MAC
+   address with the last 5 bytes set to zero.  This can be used to
+   associate the remaining prefix with a manufacturer.
+  </para>
+
+    <table id="macaddr8-functions-table">
+     <title><type>macaddr8</type> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Return Type</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>trunc</primary>
+         </indexterm>
+         <literal><function>trunc(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set last 5 bytes to zero</entry>
+        <entry><literal>trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')</literal></entry>
+        <entry><literal>12:34:56:00:00:00:00:00</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>macaddr8_set7bit</primary>
+         </indexterm>
+         <literal><function>macaddr8_set7bit(<type>macaddr8</type>)</function></literal>
+        </entry>
+        <entry><type>macaddr8</type></entry>
+        <entry>set 7th bit to one, also known as modified EUI-64, for inclusion in an IPv6 address</entry>
+        <entry><literal>macaddr8_set7bit(macaddr8 '00:34:56:ab:cd:ef')</literal></entry>
+        <entry><literal>02:34:56:ff:fe:ab:cd:ef</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    The <type>macaddr8</type> type also supports the standard relational
+    operators (<literal>&gt;</literal>, <literal>&lt;=</literal>, etc.) for
+    ordering, and the bitwise arithmetic operators (<literal>~</literal>,
+    <literal>&amp;</literal> and <literal>|</literal>) for NOT, AND and OR.
+   </para>
+
   </sect1>
 
 
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f51275..1fb0184 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -16,7 +16,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \
 	float.o format_type.o formatting.o genfile.o \
 	geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \
 	int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
-	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
+	jsonfuncs.o like.o lockfuncs.o mac.o mac8.o misc.o nabstime.o name.o \
 	network.o network_gist.o network_selfuncs.o network_spgist.o \
 	numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_locale.o pg_lsn.o pg_upgrade_support.o \
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 2270b22..cd0e34b 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -1,7 +1,14 @@
-/*
- *	PostgreSQL type definitions for MAC addresses.
+/*-------------------------------------------------------------------------
+ *
+ * mac.c
+ *    PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
+ *
+ * Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *        src/backend/utils/adt/mac.c
  *
- *	src/backend/utils/adt/mac.c
+ *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 0000000..14d9dfe
--- /dev/null
+++ b/src/backend/utils/adt/mac8.c
@@ -0,0 +1,560 @@
+/*-------------------------------------------------------------------------
+ *
+ * mac8.c
+ *	  PostgreSQL type definitions for 8 byte (EUI-64) MAC addresses.
+ *
+ * EUI-48 (6 byte) MAC addresses are accepted as input and are stored in
+ * EUI-64 format, with the 4rd and 5th bytes set to FF and FE, respectively.
+ *
+ * Output is always in 8 byte (EUI-64) format.
+ *
+ * The following code is written with the assumption that the OUI field
+ * size is 24 bits.
+ *
+ * Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		  src/backend/utils/adt/mac8.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/hash.h"
+#include "libpq/pqformat.h"
+#include "utils/builtins.h"
+#include "utils/inet.h"
+
+/*
+ *	Utility macros used for sorting and comparing:
+ */
+#define hibits(addr) \
+  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
+
+#define lobits(addr) \
+  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
+
+static unsigned char hex2_to_uchar(const char *str, int offset);
+
+static const int hexlookup[128] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static inline unsigned char
+hex2_to_uchar(const char *str, int offset)
+{
+	unsigned char ret = 0;
+	int			lookup;
+	const char *ptr = str + offset;
+
+	/* Handle the first character */
+	if (*ptr < 0 || *ptr >= 127)
+		goto invalid_input;
+
+	lookup = hexlookup[(unsigned char) *ptr];
+	if (lookup < 0 || lookup > 15)
+		goto invalid_input;
+
+	ret = lookup << 4;
+
+	/* Move to the second character */
+	ptr++;
+
+	if (*ptr < 0 || *ptr > 127)
+		goto invalid_input;
+
+	lookup = hexlookup[(unsigned char) *ptr];
+	if (lookup < 0 || lookup > 15)
+		goto invalid_input;
+
+	ret += lookup;
+
+	return ret;
+
+invalid_input:
+	ereport(ERROR,
+			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					str)));
+
+	/* We do not actually reach here */
+	return 0;
+}
+
+/*
+ * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
+ */
+Datum
+macaddr8_in(PG_FUNCTION_ARGS)
+{
+	const char *str = PG_GETARG_CSTRING(0);
+	const char *ptr = str;
+	macaddr8   *result;
+	unsigned char a = 0,
+				b = 0,
+				c = 0,
+				d = 0,
+				e = 0,
+				f = 0,
+				g = 0,
+				h = 0;
+	int			count = 0;
+	char		spacer = '\0';
+
+	/* skip leading spaces */
+	while (*ptr && isspace((unsigned char) *ptr))
+		ptr++;
+
+	/* digits must always come in pairs */
+	while (*ptr && *(ptr + 1))
+	{
+		/*
+		 * Attempt to decode each byte, which must be 2 hex digits in a row.
+		 * If either digit is not hex, hex2_to_uchar will throw ereport() for
+		 * us.  Either 6 or 8 byte MAC addresses are supported.
+		 */
+
+		/* Attempt to collect a byte */
+		count++;
+
+		switch (count)
+		{
+			case 1:
+				a = hex2_to_uchar(str, ptr - str);
+				break;
+			case 2:
+				b = hex2_to_uchar(str, ptr - str);
+				break;
+			case 3:
+				c = hex2_to_uchar(str, ptr - str);
+				break;
+			case 4:
+				d = hex2_to_uchar(str, ptr - str);
+				break;
+			case 5:
+				e = hex2_to_uchar(str, ptr - str);
+				break;
+			case 6:
+				f = hex2_to_uchar(str, ptr - str);
+				break;
+			case 7:
+				g = hex2_to_uchar(str, ptr - str);
+				break;
+			case 8:
+				h = hex2_to_uchar(str, ptr - str);
+				break;
+			default:
+				/* must be trailing garbage... */
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					   str)));
+		}
+
+		/* Move forward to where the next byte should be */
+		ptr += 2;
+
+		/* Check for a spacer, these are valid, anything else is not */
+		if (*ptr == ':' || *ptr == '-' || *ptr == '.')
+		{
+			/* remember the spacer used, if it changes then it isn't valid */
+			if (spacer == '\0')
+				spacer = *ptr;
+
+			/* Have to use the same spacer throughout */
+			else if (spacer != *ptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					   str)));
+
+			/* move past the spacer */
+			ptr++;
+		}
+
+		/* allow trailing whitespace after if we have 6 or 8 bytes */
+		if (count == 6 || count == 8)
+		{
+			if (isspace((unsigned char) *ptr))
+			{
+				while (*++ptr && isspace((unsigned char) *ptr));
+
+				/* If we found a space and then non-space, it's invalid */
+				if (*ptr)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+							 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+									str)));
+			}
+		}
+	}
+
+	/* Convert a 6 byte MAC address to macaddr8 */
+	if (count == 6)
+	{
+		h = f;
+		g = e;
+		f = d;
+
+		d = 0xFF;
+		e = 0xFE;
+	}
+	else if (count != 8)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			   errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
+					  str)));
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = a;
+	result->b = b;
+	result->c = c;
+	result->d = d;
+	result->e = e;
+	result->f = f;
+	result->g = g;
+	result->h = h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * MAC8 address (EUI-64) output function. Fixed format.
+ */
+Datum
+macaddr8_out(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	char	   *result;
+
+	result = (char *) palloc(32);
+
+	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			 addr->a, addr->b, addr->c, addr->d,
+			 addr->e, addr->f, addr->g, addr->h);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
+ *
+ * The external representation is just the eight bytes, MSB first.
+ */
+Datum
+macaddr8_recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	macaddr8   *addr;
+
+	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	addr->a = pq_getmsgbyte(buf);
+	addr->b = pq_getmsgbyte(buf);
+	addr->c = pq_getmsgbyte(buf);
+
+	if (buf->len == 6)
+	{
+		addr->d = 0xFF;
+		addr->e = 0xFE;
+	}
+	else
+	{
+		addr->d = pq_getmsgbyte(buf);
+		addr->e = pq_getmsgbyte(buf);
+	}
+
+	addr->f = pq_getmsgbyte(buf);
+	addr->g = pq_getmsgbyte(buf);
+	addr->h = pq_getmsgbyte(buf);
+
+	PG_RETURN_MACADDR8_P(addr);
+}
+
+/*
+ * macaddr8_send - converts macaddr8(EUI-64) to binary format
+ */
+Datum
+macaddr8_send(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendbyte(&buf, addr->a);
+	pq_sendbyte(&buf, addr->b);
+	pq_sendbyte(&buf, addr->c);
+	pq_sendbyte(&buf, addr->d);
+	pq_sendbyte(&buf, addr->e);
+	pq_sendbyte(&buf, addr->f);
+	pq_sendbyte(&buf, addr->g);
+	pq_sendbyte(&buf, addr->h);
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
+/*
+ * macaddr8_cmp_internal - comparison function for sorting:
+ */
+static int32
+macaddr8_cmp_internal(macaddr8 * a1, macaddr8 * a2)
+{
+	if (hibits(a1) < hibits(a2))
+		return -1;
+	else if (hibits(a1) > hibits(a2))
+		return 1;
+	else if (lobits(a1) < lobits(a2))
+		return -1;
+	else if (lobits(a1) > lobits(a2))
+		return 1;
+	else
+		return 0;
+}
+
+Datum
+macaddr8_cmp(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
+}
+
+/*
+ * Boolean comparison functions.
+ */
+
+Datum
+macaddr8_lt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
+}
+
+Datum
+macaddr8_le(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
+}
+
+Datum
+macaddr8_eq(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
+}
+
+Datum
+macaddr8_ge(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
+}
+
+Datum
+macaddr8_gt(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
+}
+
+Datum
+macaddr8_ne(PG_FUNCTION_ARGS)
+{
+	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
+
+	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
+}
+
+/*
+ * Support function for hash indexes on macaddr8.
+ */
+Datum
+hashmacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
+
+	return hash_any((unsigned char *) key, sizeof(macaddr8));
+}
+
+/*
+ * Arithmetic functions: bitwise NOT, AND, OR.
+ */
+Datum
+macaddr8_not(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = ~addr->a;
+	result->b = ~addr->b;
+	result->c = ~addr->c;
+	result->d = ~addr->d;
+	result->e = ~addr->e;
+	result->f = ~addr->f;
+	result->g = ~addr->g;
+	result->h = ~addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_and(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a & addr2->a;
+	result->b = addr1->b & addr2->b;
+	result->c = addr1->c & addr2->c;
+	result->d = addr1->d & addr2->d;
+	result->e = addr1->e & addr2->e;
+	result->f = addr1->f & addr2->f;
+	result->g = addr1->g & addr2->g;
+	result->h = addr1->h & addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8_or(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+	result->a = addr1->a | addr2->a;
+	result->b = addr1->b | addr2->b;
+	result->c = addr1->c | addr2->c;
+	result->d = addr1->d | addr2->d;
+	result->e = addr1->e | addr2->e;
+	result->f = addr1->f | addr2->f;
+	result->g = addr1->g | addr2->g;
+	result->h = addr1->h | addr2->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Truncation function to allow comparing macaddr8 manufacturers.
+ */
+Datum
+macaddr8_trunc(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = 0;
+	result->e = 0;
+	result->f = 0;
+	result->g = 0;
+	result->h = 0;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*
+ * Set 7th bit for modified EUI-64 as used in IPv6.
+ */
+Datum
+macaddr8_set7bit(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr->a | 0x02;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->d;
+	result->e = addr->e;
+	result->f = addr->f;
+	result->g = addr->g;
+	result->h = addr->h;
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+/*----------------------------------------------------------
+ *	Conversion operators.
+ *---------------------------------------------------------*/
+
+Datum
+macaddrtomacaddr8(PG_FUNCTION_ARGS)
+{
+	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
+	macaddr8   *result;
+
+	result = (macaddr8 *) palloc0(sizeof(macaddr8));
+
+	result->a = addr6->a;
+	result->b = addr6->b;
+	result->c = addr6->c;
+	result->d = 0xFF;
+	result->e = 0xFE;
+	result->f = addr6->d;
+	result->g = addr6->e;
+	result->h = addr6->f;
+
+
+	PG_RETURN_MACADDR8_P(result);
+}
+
+Datum
+macaddr8tomacaddr(PG_FUNCTION_ARGS)
+{
+	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
+	macaddr    *result;
+
+	result = (macaddr *) palloc0(sizeof(macaddr));
+
+	if ((addr->d != 0xFF) || (addr->e != 0xFE))
+		ereport(ERROR,
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+				 errmsg("macaddr8 data out of range to convert to macaddr"),
+			   errhint("Only addresses that have FF and FE as values in the "
+					   "4th and 5th bytes, from the left, for example: "
+					 "XX-XX-XX-FF-FE-XX-XX-XX, are eligible to be converted "
+					   "from macaddr8 to macaddr.")));
+
+	result->a = addr->a;
+	result->b = addr->b;
+	result->c = addr->c;
+	result->d = addr->f;
+	result->e = addr->g;
+	result->f = addr->h;
+
+	PG_RETURN_MACADDR_P(result);
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index dbc557e..2459adc 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -934,6 +934,16 @@ convert_network_to_scalar(Datum value, Oid typid)
 				res += (mac->d << 16) | (mac->e << 8) | (mac->f);
 				return res;
 			}
+		case MACADDR8OID:
+			{
+				macaddr8   *mac = DatumGetMacaddr8P(value);
+				double		res;
+
+				res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
+				res *= ((double) 256) * 256 * 256 * 256;
+				res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
+				return res;
+			}
 	}
 
 	/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index a04fd7b..4b4c37b 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3800,6 +3800,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case INETOID:
 		case CIDROID:
 		case MACADDROID:
+		case MACADDR8OID:
 			*scaledvalue = convert_network_to_scalar(value, valuetypid);
 			*scaledlobound = convert_network_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_network_to_scalar(hibound, boundstypid);
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 0251664..da0228d 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -373,6 +373,16 @@ DATA(insert (	1984   829 829 4 s 1225 403 0 ));
 DATA(insert (	1984   829 829 5 s 1224 403 0 ));
 
 /*
+ *	btree macaddr8
+ */
+
+DATA(insert (	3371   774 774 1 s 3364 403 0 ));
+DATA(insert (	3371   774 774 2 s 3365 403 0 ));
+DATA(insert (	3371   774 774 3 s 3362 403 0 ));
+DATA(insert (	3371   774 774 4 s 3367 403 0 ));
+DATA(insert (	3371   774 774 5 s 3366 403 0 ));
+
+/*
  *	btree network
  */
 
@@ -553,6 +563,8 @@ DATA(insert (	1977   20 23 1 s	416  405 0 ));
 DATA(insert (	1983   1186 1186 1 s 1330 405 0 ));
 /* macaddr_ops */
 DATA(insert (	1985   829 829 1 s 1220 405 0 ));
+/* macaddr8_ops */
+DATA(insert (	3372   774 774 1 s 3362 405 0 ));
 /* name_ops */
 DATA(insert (	1987   19 19 1 s	93	405 0 ));
 /* oid_ops */
@@ -999,6 +1011,12 @@ DATA(insert (	4074	829  829 2 s	  1223	  3580 0 ));
 DATA(insert (	4074	829  829 3 s	  1220	  3580 0 ));
 DATA(insert (	4074	829  829 4 s	  1225	  3580 0 ));
 DATA(insert (	4074	829  829 5 s	  1224	  3580 0 ));
+/* minmax macaddr8 */
+DATA(insert (	4109	774  774 1 s	  3364	  3580 0 ));
+DATA(insert (	4109	774  774 2 s	  3365	  3580 0 ));
+DATA(insert (	4109	774  774 3 s	  3362	  3580 0 ));
+DATA(insert (	4109	774  774 4 s	  3367	  3580 0 ));
+DATA(insert (	4109	774  774 5 s	  3366	  3580 0 ));
 /* minmax inet */
 DATA(insert (	4075	869  869 1 s	  1203	  3580 0 ));
 DATA(insert (	4075	869  869 2 s	  1204	  3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index f1a52ce..a87ec42 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -142,6 +142,7 @@ DATA(insert (	2968   2950 2950 2 3300 ));
 DATA(insert (	2994   2249 2249 1 2987 ));
 DATA(insert (	3194   2249 2249 1 3187 ));
 DATA(insert (	3253   3220 3220 1 3251 ));
+DATA(insert (	3371   774 774 1 4119 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 DATA(insert (	3626   3614 3614 1 3622 ));
 DATA(insert (	3683   3615 3615 1 3668 ));
@@ -182,6 +183,7 @@ DATA(insert (	2231   1042 1042 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3254   3220 3220 1 3252 ));
+DATA(insert (	3372   774 774 1 328 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 DATA(insert (	3903   3831 3831 1 3902 ));
 DATA(insert (	4034   3802 3802 1 4045 ));
@@ -414,6 +416,11 @@ DATA(insert (	4074   829	 829  1  3383 ));
 DATA(insert (	4074   829	 829  2  3384 ));
 DATA(insert (	4074   829	 829  3  3385 ));
 DATA(insert (	4074   829	 829  4  3386 ));
+/* minmax macaddr8 */
+DATA(insert (	4109   774	 774  1  3383 ));
+DATA(insert (	4109   774	 774  2  3384 ));
+DATA(insert (	4109   774	 774  3  3385 ));
+DATA(insert (	4109   774	 774  4  3386 ));
 /* minmax inet */
 DATA(insert (	4075   869	 869  1  3383 ));
 DATA(insert (	4075   869	 869  2  3384 ));
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 80a40ab..ce8dc59 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -304,6 +304,12 @@ DATA(insert (  718	603 1480 e f ));
 DATA(insert (  718	604 1544 e f ));
 
 /*
+ * MAC address category
+ */
+DATA(insert (  829	774    4123 i f ));
+DATA(insert (  774	829    4124 i f ));
+
+/*
  * INET category
  */
 DATA(insert (  650	869    0 i b ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c..5819d53 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -127,6 +127,8 @@ DATA(insert (	403		interval_ops		PGNSP PGUID 1982 1186 t 0 ));
 DATA(insert (	405		interval_ops		PGNSP PGUID 1983 1186 t 0 ));
 DATA(insert (	403		macaddr_ops			PGNSP PGUID 1984  829 t 0 ));
 DATA(insert (	405		macaddr_ops			PGNSP PGUID 1985  829 t 0 ));
+DATA(insert (	403		macaddr8_ops		PGNSP PGUID 3371  774 t 0 ));
+DATA(insert (	405		macaddr8_ops		PGNSP PGUID 3372  774 t 0 ));
 /*
  * Here's an ugly little hack to save space in the system catalog indexes.
  * btree doesn't ordinarily allow a storage type different from input type;
@@ -224,6 +226,7 @@ DATA(insert (	3580	float8_minmax_ops		PGNSP PGUID 4070   701 t 701 ));
 DATA(insert (	3580	abstime_minmax_ops		PGNSP PGUID 4072   702 t 702 ));
 DATA(insert (	3580	reltime_minmax_ops		PGNSP PGUID 4073   703 t 703 ));
 DATA(insert (	3580	macaddr_minmax_ops		PGNSP PGUID 4074   829 t 829 ));
+DATA(insert (	3580	macaddr8_minmax_ops		PGNSP PGUID 4109   774 t 774 ));
 DATA(insert (	3580	inet_minmax_ops			PGNSP PGUID 4075   869 f 869 ));
 DATA(insert (	3580	inet_inclusion_ops		PGNSP PGUID 4102   869 t 869 ));
 DATA(insert (	3580	bpchar_minmax_ops		PGNSP PGUID 4076  1042 t 1042 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 45feb69..fe8795a 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1119,7 +1119,7 @@ DESCR("equal");
 DATA(insert OID = 1617 (  "#"	  PGNSP PGUID b f f  628	628  600 1617  0 line_interpt - - ));
 DESCR("intersection point");
 
-/* MAC type */
+/* MACADDR type */
 DATA(insert OID = 1220 (  "="	   PGNSP PGUID b t t 829 829	 16 1220 1221 macaddr_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1221 (  "<>"	   PGNSP PGUID b f f 829 829	 16 1221 1220 macaddr_ne neqsel neqjoinsel ));
@@ -1140,6 +1140,27 @@ DESCR("bitwise and");
 DATA(insert OID = 3149 (  "|"	   PGNSP PGUID b f f	829 829 829 0 0 macaddr_or - - ));
 DESCR("bitwise or");
 
+/* MACADDR8 type */
+DATA(insert OID = 3362 (  "="	   PGNSP PGUID b t t 774 774	 16 3362 3363 macaddr8_eq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 3363 (  "<>"	   PGNSP PGUID b f f 774 774	 16 3363 3362 macaddr8_ne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 3364 (  "<"	   PGNSP PGUID b f f 774 774	 16 3366 3367 macaddr8_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+DATA(insert OID = 3365 (  "<="	   PGNSP PGUID b f f 774 774	 16 3367 3366 macaddr8_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+DATA(insert OID = 3366 (  ">"	   PGNSP PGUID b f f 774 774	 16 3364 3365 macaddr8_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 3367 (  ">="	   PGNSP PGUID b f f 774 774	 16 3365 3364 macaddr8_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
+DATA(insert OID = 3368 (  "~"	   PGNSP PGUID l f f	  0 774 774 0 0 macaddr8_not - - ));
+DESCR("bitwise not");
+DATA(insert OID = 3369 (  "&"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_and - - ));
+DESCR("bitwise and");
+DATA(insert OID = 3370 (  "|"	   PGNSP PGUID b f f	774 774 774 0 0 macaddr8_or - - ));
+DESCR("bitwise or");
+
 /* INET type (these also support CIDR via implicit cast) */
 DATA(insert OID = 1201 (  "="	   PGNSP PGUID b t t 869 869	 16 1201 1202 network_eq eqsel eqjoinsel ));
 DESCR("equal");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index bd673fe..546527a 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -87,6 +87,8 @@ DATA(insert OID = 1982 (	403		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1983 (	405		interval_ops	PGNSP PGUID ));
 DATA(insert OID = 1984 (	403		macaddr_ops		PGNSP PGUID ));
 DATA(insert OID = 1985 (	405		macaddr_ops		PGNSP PGUID ));
+DATA(insert OID = 3371 (	403		macaddr8_ops	PGNSP PGUID ));
+DATA(insert OID = 3372 (	405		macaddr8_ops	PGNSP PGUID ));
 DATA(insert OID = 1986 (	403		name_ops		PGNSP PGUID ));
 #define NAME_BTREE_FAM_OID 1986
 DATA(insert OID = 1987 (	405		name_ops		PGNSP PGUID ));
@@ -171,6 +173,7 @@ DATA(insert OID = 4070 (	3580	float_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4072 (	3580	abstime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4073 (	3580	reltime_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4074 (	3580	macaddr_minmax_ops		PGNSP PGUID ));
+DATA(insert OID = 4109 (	3580	macaddr8_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4075 (	3580	network_minmax_ops		PGNSP PGUID ));
 DATA(insert OID = 4102 (	3580	network_inclusion_ops	PGNSP PGUID ));
 DATA(insert OID = 4076 (	3580	bpchar_minmax_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ec4aedb..3d5d866 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -692,6 +692,8 @@ DATA(insert OID = 422 (  hashinet		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0
 DESCR("hash");
 DATA(insert OID = 432 (  hash_numeric	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "1700" _null_ _null_ _null_ _null_ _null_ hash_numeric _null_ _null_ _null_ ));
 DESCR("hash");
+DATA(insert OID = 328 (  hashmacaddr8	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "774" _null_ _null_ _null_ _null_ _null_ hashmacaddr8 _null_ _null_ _null_ ));
+DESCR("hash");
 
 DATA(insert OID = 438 (  num_nulls		   PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_ pg_num_nulls _null_ _null_ _null_ ));
 DESCR("count the number of NULL arguments");
@@ -2098,14 +2100,14 @@ DESCR("get bit");
 DATA(insert OID = 3033 (  set_bit		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
 DESCR("set bit");
 
-/* for mac type support */
+/* for macaddr type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "2275" _null_ _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "829" _null_ _null_ _null_ _null_ _null_ macaddr_out _null_ _null_ _null_ ));
 DESCR("I/O");
 
 DATA(insert OID = 753 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "829" _null_ _null_ _null_ _null_ _null_ macaddr_trunc _null_ _null_ _null_ ));
-DESCR("MAC manufacturer fields");
+DESCR("MACADDR manufacturer fields");
 
 DATA(insert OID = 830 (  macaddr_eq			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_eq _null_ _null_ _null_ ));
 DATA(insert OID = 831 (  macaddr_lt			PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "829 829" _null_ _null_ _null_ _null_ _null_	macaddr_lt _null_ _null_ _null_ ));
@@ -2119,6 +2121,33 @@ DATA(insert OID = 3144 (  macaddr_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1
 DATA(insert OID = 3145 (  macaddr_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_and _null_ _null_ _null_ ));
 DATA(insert OID = 3146 (  macaddr_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 829 "829 829" _null_ _null_ _null_ _null_ _null_ macaddr_or _null_ _null_ _null_ ));
 
+/* for macaddr8 type support */
+DATA(insert OID = 4110 (  macaddr8_in		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2275" _null_ _null_ _null_ _null_ _null_ macaddr8_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4111 (  macaddr8_out		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+DATA(insert OID = 4112 (  trunc				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_trunc _null_ _null_ _null_ ));
+DESCR("MACADDR8 manufacturer fields");
+
+DATA(insert OID = 4113 (  macaddr8_eq		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_eq _null_ _null_ _null_ ));
+DATA(insert OID = 4114 (  macaddr8_lt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_lt _null_ _null_ _null_ ));
+DATA(insert OID = 4115 (  macaddr8_le		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_le _null_ _null_ _null_ ));
+DATA(insert OID = 4116 (  macaddr8_gt		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_gt _null_ _null_ _null_ ));
+DATA(insert OID = 4117 (  macaddr8_ge		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ge _null_ _null_ _null_ ));
+DATA(insert OID = 4118 (  macaddr8_ne		PGNSP PGUID 12 1 0 0 0 f f f t t f i s 2 0 16 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_ne _null_ _null_ _null_ ));
+DATA(insert OID = 4119 (  macaddr8_cmp		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "774 774" _null_ _null_ _null_ _null_ _null_	macaddr8_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+DATA(insert OID = 4120 (  macaddr8_not		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_not _null_ _null_ _null_ ));
+DATA(insert OID = 4121 (  macaddr8_and		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_and _null_ _null_ _null_ ));
+DATA(insert OID = 4122 (  macaddr8_or		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 774 "774 774" _null_ _null_ _null_ _null_ _null_ macaddr8_or _null_ _null_ _null_ ));
+DATA(insert OID = 4123 (  macaddr8			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "829" _null_ _null_ _null_ _null_ _null_ macaddrtomacaddr8 _null_ _null_ _null_ ));
+DESCR("convert macaddr to macaddr8");
+DATA(insert OID = 4124 (  macaddr			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 829 "774" _null_ _null_ _null_ _null_ _null_ macaddr8tomacaddr _null_ _null_ _null_ ));
+DESCR("convert macaddr8 to macaddr");
+DATA(insert OID = 4125 (  macaddr8_set7bit	PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_set7bit _null_ _null_ _null_ ));
+DESCR("set 7th bit in macaddr8");
+
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 869 "2275" _null_ _null_ _null_ _null_ _null_ inet_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -4056,6 +4085,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "2278" _null_ _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3446 (  macaddr8_recv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 774 "2281" _null_ _null_ _null_ _null_ _null_ macaddr8_recv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3447 (  macaddr8_send		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 17 "774" _null_ _null_ _null_ _null_ _null_ macaddr8_send _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 16" _null_ _null_ _null_ _null_ _null_ pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 6e4c65e..9f61238 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -441,6 +441,9 @@ DESCR("IP address/netmask, host address, netmask optional");
 DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
+DATA(insert OID = 774 ( macaddr8	PGNSP PGUID 8 f b U f t \054 0 0 775 macaddr8_in macaddr8_out macaddr8_recv macaddr8_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("XX:XX:XX:XX:XX:XX:XX:XX, MAC address");
+#define MACADDR8OID 774
 
 /* OIDS 900 - 999 */
 
@@ -482,6 +485,7 @@ DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b A f t \054 0  829 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
+DATA(insert OID = 775  (  _macaddr8  PGNSP PGUID -1 f b A f t \054 0  774 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1041 (  _inet		 PGNSP PGUID -1 f b A f t \054 0  869 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 651  (  _cidr		 PGNSP PGUID -1 f b A f t \054 0  650 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1263 (  _cstring	 PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 577b34d..3f60280 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -102,6 +102,21 @@ typedef struct macaddr
 } macaddr;
 
 /*
+ *	This is the internal storage format for MAC8 addresses:
+ */
+typedef struct macaddr8
+{
+	unsigned char a;
+	unsigned char b;
+	unsigned char c;
+	unsigned char d;
+	unsigned char e;
+	unsigned char f;
+	unsigned char g;
+	unsigned char h;
+} macaddr8;
+
+/*
  * fmgr interface macros
  */
 #define DatumGetInetP(X)	((inet *) PG_DETOAST_DATUM(X))
@@ -110,12 +125,19 @@ typedef struct macaddr
 #define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
 #define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n))
 #define PG_RETURN_INET_P(x) return InetPGetDatum(x)
+
 /* macaddr is a fixed-length pass-by-reference datatype */
 #define DatumGetMacaddrP(X)    ((macaddr *) DatumGetPointer(X))
 #define MacaddrPGetDatum(X)    PointerGetDatum(X)
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/* macaddr8 is a fixed-length pass-by-reference datatype */
+#define DatumGetMacaddr8P(X)	((macaddr8 *) DatumGetPointer(X))
+#define Macaddr8PGetDatum(X)	PointerGetDatum(X)
+#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n))
+#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x)
+
 /*
  * Support functions in network.c
  */
diff --git a/src/test/regress/expected/macaddr8.out b/src/test/regress/expected/macaddr8.out
new file mode 100644
index 0000000..bd83b68
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,355 @@
+--
+-- macaddr8
+--
+-- test various cases of valid and invalid input
+-- valid
+SELECT '08:00:2b:01:02:03     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '    08:00:2b:01:02:03     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '    08:00:2b:01:02:03'::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:ff:fe:01:02:03
+(1 row)
+
+SELECT '08:00:2b:01:02:03:04:05     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '    08:00:2b:01:02:03:04:05     '::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '    08:00:2b:01:02:03:04:05'::macaddr8;
+        macaddr8         
+-------------------------
+ 08:00:2b:01:02:03:04:05
+(1 row)
+
+SELECT '123    08:00:2b:01:02:03'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "123    08:00:2b:01:02:03"
+LINE 1: SELECT '123    08:00:2b:01:02:03'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03  123'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03  123"
+LINE 1: SELECT '08:00:2b:01:02:03  123'::macaddr8;
+               ^
+SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "123    08:00:2b:01:02:03:04:05"
+LINE 1: SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:05  123"
+LINE 1: SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8;
+               ^
+SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01:02:03:04:05:06:07"
+LINE 1: SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8;
+               ^
+SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08-00-2b-01-02-03-04-05-06-07"
+LINE 1: SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8;
+               ^
+SELECT '08002b:01020304050607'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b:01020304050607"
+LINE 1: SELECT '08002b:01020304050607'::macaddr8;
+               ^
+SELECT '08002b01020304050607'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b01020304050607"
+LINE 1: SELECT '08002b01020304050607'::macaddr8;
+               ^
+SELECT '0z002b0102030405'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "0z002b0102030405"
+LINE 1: SELECT '0z002b0102030405'::macaddr8;
+               ^
+SELECT '08002b010203xyza'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08002b010203xyza"
+LINE 1: SELECT '08002b010203xyza'::macaddr8;
+               ^
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00-2b:01:02:03:04:05"
+LINE 1: SELECT '08:00-2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00-2b:01:02:03:04:05"
+LINE 1: SELECT '08:00-2b:01:02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01.02:03:04:05"
+LINE 1: SELECT '08:00:2b:01.02:03:04:05'::macaddr8;
+               ^
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+ERROR:  invalid input syntax for type macaddr8: "08:00:2b:01.02:03:04:05"
+LINE 1: SELECT '08:00:2b:01.02:03:04:05'::macaddr8;
+               ^
+-- test converting a MAC address to modified EUI-64 for inclusion
+-- in an ipv6 address
+SELECT macaddr8_set7bit('00:08:2b:01:02:03'::macaddr8);
+    macaddr8_set7bit     
+-------------------------
+ 02:08:2b:ff:fe:01:02:03
+(1 row)
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+ERROR:  invalid input syntax for type macaddr8: "not even close"
+LINE 1: INSERT INTO macaddr8_data VALUES (9, 'not even close');
+                                             ^
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+SELECT * FROM macaddr8_data ORDER BY 1;
+ a  |            b            
+----+-------------------------
+  1 | 08:00:2b:ff:fe:01:02:03
+  2 | 08:00:2b:ff:fe:01:02:03
+  3 | 08:00:2b:ff:fe:01:02:03
+  4 | 08:00:2b:ff:fe:01:02:03
+  5 | 08:00:2b:ff:fe:01:02:03
+  6 | 08:00:2b:ff:fe:01:02:03
+  7 | 08:00:2b:ff:fe:01:02:03
+  8 | 08:00:2b:ff:fe:01:02:03
+ 10 | 08:00:2b:ff:fe:01:02:04
+ 11 | 08:00:2b:ff:fe:01:02:02
+ 12 | 08:00:2a:ff:fe:01:02:03
+ 13 | 08:00:2c:ff:fe:01:02:03
+ 14 | 08:00:2a:ff:fe:01:02:04
+ 15 | 08:00:2b:01:02:03:04:05
+ 16 | 08:00:2b:01:02:03:04:05
+ 17 | 08:00:2b:01:02:03:04:05
+ 18 | 08:00:2b:01:02:03:04:05
+ 19 | 08:00:2b:01:02:03:04:05
+ 20 | 08:00:2b:01:02:03:04:05
+ 21 | 08:00:2b:01:02:03:04:05
+(20 rows)
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+WARNING:  hash indexes are not WAL-logged and their use is discouraged
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+ a  |            b            |          trunc          
+----+-------------------------+-------------------------
+ 12 | 08:00:2a:ff:fe:01:02:03 | 08:00:2a:00:00:00:00:00
+ 14 | 08:00:2a:ff:fe:01:02:04 | 08:00:2a:00:00:00:00:00
+ 15 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 16 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 17 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 18 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 19 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 20 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 21 | 08:00:2b:01:02:03:04:05 | 08:00:2b:00:00:00:00:00
+ 11 | 08:00:2b:ff:fe:01:02:02 | 08:00:2b:00:00:00:00:00
+  1 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  2 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  3 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  4 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  5 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  6 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  7 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+  8 | 08:00:2b:ff:fe:01:02:03 | 08:00:2b:00:00:00:00:00
+ 10 | 08:00:2b:ff:fe:01:02:04 | 08:00:2b:00:00:00:00:00
+ 13 | 08:00:2c:ff:fe:01:02:03 | 08:00:2c:00:00:00:00:00
+(20 rows)
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT ~b                       FROM macaddr8_data;
+        ?column?         
+-------------------------
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fc
+ f7:ff:d4:00:01:fe:fd:fb
+ f7:ff:d4:00:01:fe:fd:fd
+ f7:ff:d5:00:01:fe:fd:fc
+ f7:ff:d3:00:01:fe:fd:fc
+ f7:ff:d5:00:01:fe:fd:fb
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+ f7:ff:d4:fe:fd:fc:fb:fa
+(20 rows)
+
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:ff:fe:01:02:02
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:03
+ 00:00:00:ff:fe:01:02:04
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+ 00:00:00:01:02:03:04:05
+(20 rows)
+
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+        ?column?         
+-------------------------
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:05:07:07
+ 09:02:2f:ff:fe:05:07:07
+ 09:02:2b:ff:fe:05:07:06
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+ 09:02:2b:ff:fe:07:05:07
+(20 rows)
+
+DROP TABLE macaddr8_data;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 0bcec13..64d9dd6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -685,6 +685,12 @@ uuid_gt(uuid,uuid)
 uuid_ne(uuid,uuid)
 xidneq(xid,xid)
 xidneqint4(xid,integer)
+macaddr8_eq(macaddr8,macaddr8)
+macaddr8_lt(macaddr8,macaddr8)
+macaddr8_le(macaddr8,macaddr8)
+macaddr8_gt(macaddr8,macaddr8)
+macaddr8_ge(macaddr8,macaddr8)
+macaddr8_ne(macaddr8,macaddr8)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 9f38349..ea7b5b4 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -23,7 +23,7 @@ test: numerology
 # ----------
 # The second group of parallel tests
 # ----------
-test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr tstypes comments
+test: point lseg line box path polygon circle date time timetz timestamp timestamptz interval abstime reltime tinterval inet macaddr macaddr8 tstypes comments
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 2987b24..cf48ea7 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -41,6 +41,7 @@ test: reltime
 test: tinterval
 test: inet
 test: macaddr
+test: macaddr8
 test: tstypes
 test: comments
 test: geometry
diff --git a/src/test/regress/sql/macaddr8.sql b/src/test/regress/sql/macaddr8.sql
new file mode 100644
index 0000000..57a227c
--- /dev/null
+++ b/src/test/regress/sql/macaddr8.sql
@@ -0,0 +1,89 @@
+--
+-- macaddr8
+--
+
+-- test various cases of valid and invalid input
+-- valid
+SELECT '08:00:2b:01:02:03     '::macaddr8;
+SELECT '    08:00:2b:01:02:03     '::macaddr8;
+SELECT '    08:00:2b:01:02:03'::macaddr8;
+SELECT '08:00:2b:01:02:03:04:05     '::macaddr8;
+SELECT '    08:00:2b:01:02:03:04:05     '::macaddr8;
+SELECT '    08:00:2b:01:02:03:04:05'::macaddr8;
+
+SELECT '123    08:00:2b:01:02:03'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03  123'::macaddr8; -- invalid
+SELECT '123    08:00:2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03:04:05  123'::macaddr8; -- invalid
+SELECT '08:00:2b:01:02:03:04:05:06:07'::macaddr8; -- invalid
+SELECT '08-00-2b-01-02-03-04-05-06-07'::macaddr8; -- invalid
+SELECT '08002b:01020304050607'::macaddr8; -- invalid
+SELECT '08002b01020304050607'::macaddr8; -- invalid
+SELECT '0z002b0102030405'::macaddr8; -- invalid
+SELECT '08002b010203xyza'::macaddr8; -- invalid
+
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00-2b:01:02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+SELECT '08:00:2b:01.02:03:04:05'::macaddr8; -- invalid
+
+-- test converting a MAC address to modified EUI-64 for inclusion
+-- in an ipv6 address
+SELECT macaddr8_set7bit('00:08:2b:01:02:03'::macaddr8);
+
+CREATE TABLE macaddr8_data (a int, b macaddr8);
+
+INSERT INTO macaddr8_data VALUES (1, '08:00:2b:01:02:03');
+INSERT INTO macaddr8_data VALUES (2, '08-00-2b-01-02-03');
+INSERT INTO macaddr8_data VALUES (3, '08002b:010203');
+INSERT INTO macaddr8_data VALUES (4, '08002b-010203');
+INSERT INTO macaddr8_data VALUES (5, '0800.2b01.0203');
+INSERT INTO macaddr8_data VALUES (6, '0800-2b01-0203');
+INSERT INTO macaddr8_data VALUES (7, '08002b010203');
+INSERT INTO macaddr8_data VALUES (8, '0800:2b01:0203');
+INSERT INTO macaddr8_data VALUES (9, 'not even close'); -- invalid
+
+INSERT INTO macaddr8_data VALUES (10, '08:00:2b:01:02:04');
+INSERT INTO macaddr8_data VALUES (11, '08:00:2b:01:02:02');
+INSERT INTO macaddr8_data VALUES (12, '08:00:2a:01:02:03');
+INSERT INTO macaddr8_data VALUES (13, '08:00:2c:01:02:03');
+INSERT INTO macaddr8_data VALUES (14, '08:00:2a:01:02:04');
+
+INSERT INTO macaddr8_data VALUES (15, '08:00:2b:01:02:03:04:05');
+INSERT INTO macaddr8_data VALUES (16, '08-00-2b-01-02-03-04-05');
+INSERT INTO macaddr8_data VALUES (17, '08002b:0102030405');
+INSERT INTO macaddr8_data VALUES (18, '08002b-0102030405');
+INSERT INTO macaddr8_data VALUES (19, '0800.2b01.0203.0405');
+INSERT INTO macaddr8_data VALUES (20, '08002b01:02030405');
+INSERT INTO macaddr8_data VALUES (21, '08002b0102030405');
+
+SELECT * FROM macaddr8_data ORDER BY 1;
+
+CREATE INDEX macaddr8_data_btree ON macaddr8_data USING btree (b);
+CREATE INDEX macaddr8_data_hash ON macaddr8_data USING hash (b);
+
+SELECT a, b, trunc(b) FROM macaddr8_data ORDER BY 2, 1;
+
+SELECT b <  '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b >  '08:00:2b:ff:fe:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b >  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b::macaddr <= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr >= '08:00:2b:01:02:04' FROM macaddr8_data WHERE a = 1; -- false
+SELECT b =  '08:00:2b:ff:fe:01:02:03' FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:04'::macaddr FROM macaddr8_data WHERE a = 1; -- true
+SELECT b::macaddr <> '08:00:2b:01:02:03'::macaddr FROM macaddr8_data WHERE a = 1; -- false
+
+SELECT b <  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >  '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b >  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b <= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b >= '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- false
+SELECT b =  '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:06' FROM macaddr8_data WHERE a = 15; -- true
+SELECT b <> '08:00:2b:01:02:03:04:05' FROM macaddr8_data WHERE a = 15; -- false
+
+SELECT ~b                       FROM macaddr8_data;
+SELECT  b & '00:00:00:ff:ff:ff' FROM macaddr8_data;
+SELECT  b | '01:02:03:04:05:06' FROM macaddr8_data;
+
+DROP TABLE macaddr8_data;
-- 
2.7.4

#67Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Stephen Frost (#65)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On Mon, Mar 13, 2017 at 6:38 AM, Stephen Frost <sfrost@snowman.net> wrote:

Greetings,

* Stephen Frost (sfrost@snowman.net) wrote:

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <

vitaly.burovoy@gmail.com> wrote:

The new status of this patch is: Ready for Committer

Thanks for the review.

I've started taking a look at this with an eye towards committing it
soon.

I've spent a good bit of time going over this, possibly even more than
it was worth, but hopefully we'll see people making use of this data
type with PG10 and as more IPv6 deployment happens.

Thanks for the review.

Of particular note, I rewrote macaddr8_in to not use sscanf().
sscanf(), at least on my system, would accept negative values even for
'%2x', leading to slightly odd errors with certain inputs, including
with our existing macaddr type:

=# select '00-203040506'::macaddr;
ERROR: invalid octet value in "macaddr" value: "00-203040506"
LINE 1: select '00-203040506'::macaddr;

With my rewrite, the macaddr8 type will throw a clearer (in my view, at
least) error:

=# select '00-203040506'::macaddr8;
ERROR: invalid input syntax for type macaddr8: "00-203040506"
LINE 1: select '00-203040506'::macaddr8;

One other point is that the previously disallowed format with just two
colons ('0800:2b01:0203') is now allowed. Given that both the two dot
format ('0800.2b01.0203') and the two dash format ('0800-2b01-0203')
were accepted, this seemed alright to me. Is there really a good reason
to disallow the two colon format?

No. There is no special reason to disallow.
The rewrite of macaddr8_in will allow all possible combinations of spacers.

I also thought about what we expect the usage of macaddr8 to be and
realized that we should really have a function to help go from EUI-48 to
the IPv6 Modified EUI-64 format, since users will almost certainly want
to do exactly that. As such, I added a macaddr8_set7bit() function
which will perform the EUI-64 -> Modified EUI-64 change (which is just
setting the 7th bit) and added associated documentation and reasoning
for why that function exists.

I checked and it is working as expected.

Regards,
Hari Babu
Fujitsu Australia

#68Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Stephen Frost (#66)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On Mon, Mar 13, 2017 at 6:52 AM, Stephen Frost <sfrost@snowman.net> wrote:

Greetings,

* Stephen Frost (sfrost@snowman.net) wrote:

* Stephen Frost (sfrost@snowman.net) wrote:

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <

vitaly.burovoy@gmail.com> wrote:

The new status of this patch is: Ready for Committer

Thanks for the review.

I've started taking a look at this with an eye towards committing it
soon.

I've spent a good bit of time going over this, possibly even more than
it was worth, but hopefully we'll see people making use of this data
type with PG10 and as more IPv6 deployment happens.

And, naturally, re-reading the email as it hit the list made me realize
that the documentation/error-message incorrectly said "3rd and 4th"
bytes were being set to FF and FE, when it's actually the 4th and 5th
byte. The code was correct, just the documentation and the error
message had the wrong numbers. The commit message is also correct.

Thanks for the review and corrections.

I found some small corrections.

s/4rd/4th/g -- Type correction.

+ Input is accepted in the following formats:

As we are supporting many different input variants, and all combinations
are not listed, so how about changing the above statement as below.

"Following are the some of the input formats that are accepted:"

I didn't find any other problems during testing and review. The patch
is fine.

Regards,
Hari Babu
Fujitsu Australia

#69Stephen Frost
sfrost@snowman.net
In reply to: Haribabu Kommi (#68)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Greetings Hari Babu,

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Mon, Mar 13, 2017 at 6:52 AM, Stephen Frost <sfrost@snowman.net> wrote:

And, naturally, re-reading the email as it hit the list made me realize
that the documentation/error-message incorrectly said "3rd and 4th"
bytes were being set to FF and FE, when it's actually the 4th and 5th
byte. The code was correct, just the documentation and the error
message had the wrong numbers. The commit message is also correct.

Thanks for the review and corrections.

I found some small corrections.

s/4rd/4th/g -- Type correction.

+ Input is accepted in the following formats:

As we are supporting many different input variants, and all combinations
are not listed, so how about changing the above statement as below.

"Following are the some of the input formats that are accepted:"

Good points, I incorporated them along with a bit of additional
information in the documentation as to what we do actually support.

I didn't find any other problems during testing and review. The patch
is fine.

Great! I've committed this now. If you see anything additional or
other changes which should be made, please let me know.

... and bumped catversion after (thanks for the reminder, Robert!).

Thanks!

Stephen

#70Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Stephen Frost (#69)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On Thu, Mar 16, 2017 at 2:20 AM, Stephen Frost <sfrost@snowman.net> wrote:

Greetings Hari Babu,

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Mon, Mar 13, 2017 at 6:52 AM, Stephen Frost <sfrost@snowman.net>

wrote:

And, naturally, re-reading the email as it hit the list made me realize
that the documentation/error-message incorrectly said "3rd and 4th"
bytes were being set to FF and FE, when it's actually the 4th and 5th
byte. The code was correct, just the documentation and the error
message had the wrong numbers. The commit message is also correct.

Thanks for the review and corrections.

I found some small corrections.

s/4rd/4th/g -- Type correction.

+ Input is accepted in the following formats:

As we are supporting many different input variants, and all combinations
are not listed, so how about changing the above statement as below.

"Following are the some of the input formats that are accepted:"

Good points, I incorporated them along with a bit of additional
information in the documentation as to what we do actually support.

I didn't find any other problems during testing and review. The patch
is fine.

Great! I've committed this now. If you see anything additional or
other changes which should be made, please let me know.

... and bumped catversion after (thanks for the reminder, Robert!).

Thanks for the review and changes.

Regards,
Hari Babu
Fujitsu Australia

#71Andres Freund
andres@anarazel.de
In reply to: Stephen Frost (#69)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

On 2017-03-15 11:20:53 -0400, Stephen Frost wrote:

Greetings Hari Babu,

* Haribabu Kommi (kommi.haribabu@gmail.com) wrote:

On Mon, Mar 13, 2017 at 6:52 AM, Stephen Frost <sfrost@snowman.net> wrote:

And, naturally, re-reading the email as it hit the list made me realize
that the documentation/error-message incorrectly said "3rd and 4th"
bytes were being set to FF and FE, when it's actually the 4th and 5th
byte. The code was correct, just the documentation and the error
message had the wrong numbers. The commit message is also correct.

Thanks for the review and corrections.

I found some small corrections.

s/4rd/4th/g -- Type correction.

+ Input is accepted in the following formats:

As we are supporting many different input variants, and all combinations
are not listed, so how about changing the above statement as below.

"Following are the some of the input formats that are accepted:"

Good points, I incorporated them along with a bit of additional
information in the documentation as to what we do actually support.

I didn't find any other problems during testing and review. The patch
is fine.

Great! I've committed this now. If you see anything additional or
other changes which should be made, please let me know.

... and bumped catversion after (thanks for the reminder, Robert!).

I see a new warning due to, presumably, this:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c: In function ‘hex2_to_uchar’:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c:71:23: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (*ptr < 0 || *ptr > 127)
^
Andres

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#72Stephen Frost
sfrost@snowman.net
In reply to: Andres Freund (#71)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Andres,

* Andres Freund (andres@anarazel.de) wrote:

I see a new warning due to, presumably, this:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c: In function ‘hex2_to_uchar’:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c:71:23: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (*ptr < 0 || *ptr > 127)
^

Ah, yeah, I suppose I can drop that half of the check.

Will push a fix soon.

Thanks!

Stephen

#73Stephen Frost
sfrost@snowman.net
In reply to: Andres Freund (#71)
Re: [REVIEW] macaddr 64 bit (EUI-64) datatype support

Andres,

* Andres Freund (andres@anarazel.de) wrote:

I see a new warning due to, presumably, this:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c: In function ‘hex2_to_uchar’:
/home/andres/src/postgresql/src/backend/utils/adt/mac8.c:71:23: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (*ptr < 0 || *ptr > 127)

Pushed a fix for this (which also does a bit of other tidying too).

Thanks!

Stephen