Greetings,

* Stephen Frost (sfr...@snowman.net) wrote:
> * Stephen Frost (sfr...@snowman.net) wrote:
> > * Haribabu Kommi (kommi.harib...@gmail.com) wrote:
> > > On Wed, Feb 1, 2017 at 6:27 AM, Vitaly Burovoy <vitaly.buro...@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
From 5b470010cacdc32bec521b1d57ad9f60c7bd638a Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfr...@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_g...@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

Attachment: signature.asc
Description: Digital signature

Reply via email to