diff --git a/contrib/btree_gin/Makefile b/contrib/btree_gin/Makefile
index 0492091599e..f22e4af7dfb 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 00000000000..dd81d27599c
--- /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 030b61097f6..725456e9404 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -322,6 +322,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)
{
diff --git a/contrib/btree_gin/btree_gin.control b/contrib/btree_gin/btree_gin.control
index 3b2cb2d709d..d96436e8ec4 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 00000000000..025b0c171eb
--- /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 00000000000..86785c3ca98
--- /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 d36f51795d0..c70f17869a2 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 00000000000..f77f6c8380b
--- /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 ddbf83dc32f..fdf0e6ad9ee 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 9b3e22c4692..f759299bb2d 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 00000000000..13238efe328
--- /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 00000000000..e5ec6a5deab
--- /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 00000000000..61e7d7af405
--- /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 6448b18e465..5bf11dc2d15 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -281,6 +281,17 @@
>
+
+ macaddr8_minmax_ops
+ macaddr8
+
+ <
+ <=
+ =
+ >=
+ >
+
+
name_minmax_ops
name
diff --git a/doc/src/sgml/btree-gin.sgml b/doc/src/sgml/btree-gin.sgml
index 2b081db9d5a..0de8eb5c309 100644
--- a/doc/src/sgml/btree-gin.sgml
+++ b/doc/src/sgml/btree-gin.sgml
@@ -16,7 +16,8 @@
time without time zone>, date>, interval>,
oid>, money>, "char">,
varchar>, text>, bytea>, bit>,
- varbit>, macaddr>, inet>, and cidr>.
+ varbit>, macaddr>, macaddr8>, inet>,
+ and cidr>.
diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml
index d08647ce05a..cfdd5be84af 100644
--- a/doc/src/sgml/btree-gist.sgml
+++ b/doc/src/sgml/btree-gist.sgml
@@ -16,8 +16,8 @@
time without time zone>, date>, interval>,
oid>, money>, char>,
varchar>, text>, bytea>, bit>,
- varbit>, macaddr>, inet>, cidr>,
- and uuid>.
+ varbit>, macaddr>, macaddr8>, inet>,
+ cidr> and uuid>.
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 35610307d9a..e2f8dee7b66 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -166,6 +166,12 @@
MAC (Media Access Control) address
+
+ macaddr8
+
+ MAC (Media Access Control) address (EUI-64 format)
+
+
money
@@ -3428,6 +3434,12 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
MAC addresses
+
+ macaddr8
+ 8 bytes
+ MAC addresses (EUI-64 format)
+
+
@@ -3668,6 +3680,77 @@ SELECT person.name, holidays.num_weeks FROM person, holidays
+
+ macaddr8
+
+
+ macaddr8 (data type)
+
+
+
+ MAC address (EUI-64 format)
+ macaddr
+
+
+
+ The 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
+ 4th 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 macaddr8_set7bit> is provided to make this
+ change.
+
+ Generally speaking, any input which is comprised of pairs of hex
+ digits (on byte boundaries), optionally separated consistently by
+ one of ':'>, '-'> or '.'>, is
+ accepted. The number of hex digits must be either 16 (8 bytes) or
+ 12 (6 bytes). Leading and trailing whitespace is ignored.
+
+ The following are examples of input formats that are accepted:
+
+
+ '08:00:2b:01:02:03:04:05'>
+ '08-00-2b-01-02-03-04-05'>
+ '08002b:0102030405'>
+ '08002b-0102030405'>
+ '0800.2b01.0203.0405'>
+ '0800-2b01-0203-0405'>
+ '08002b01:02030405'>
+ '08002b0102030405'>
+
+
+ These examples would all specify the same address. Upper and
+ lower case is accepted for the digits
+ a> through f>. Output is always in the
+ first of the forms shown.
+
+ The last six input formats that are mentioned above are not part
+ of any standard.
+
+ 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 macaddr8_set7bit> as shown:
+
+
+SELECT macaddr8_set7bit('08:00:2b:01:02:03');
+
+ macaddr8_set7bit
+-------------------------
+ 0a:00:2b:ff:fe:01:02:03
+(1 row)
+
+
+
+
+
+
+
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 583b3b241ab..a521912317b 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.
+
+ shows the functions
+ available for use with the macaddr8 type. The function
+ trunc(macaddr8) returns a MAC
+ address with the last 5 bytes set to zero. This can be used to
+ associate the remaining prefix with a manufacturer.
+
+
+
+ macaddr8 Functions
+
+
+
+ Function
+ Return Type
+ Description
+ Example
+ Result
+
+
+
+
+
+
+ trunc
+
+ trunc(macaddr8)
+
+ macaddr8
+ set last 5 bytes to zero
+ trunc(macaddr8 '12:34:56:78:90:ab:cd:ef')
+ 12:34:56:00:00:00:00:00
+
+
+
+
+ macaddr8_set7bit
+
+ macaddr8_set7bit(macaddr8)
+
+ macaddr8
+ set 7th bit to one, also known as modified EUI-64, for inclusion in an IPv6 address
+ macaddr8_set7bit(macaddr8 '00:34:56:ab:cd:ef')
+ 02:34:56:ff:fe:ab:cd:ef
+
+
+
+
+
+
+ The macaddr8 type also supports the standard relational
+ operators (>, <=, etc.) for
+ ordering, and the bitwise arithmetic operators (~,
+ & and |) for NOT, AND and OR.
+
+
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 0f512753e49..1fb018416ef 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 2270b223eab..a1e9c53b730 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.
+/*-------------------------------------------------------------------------
*
- * src/backend/utils/adt/mac.c
+ * 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
+ *
+ *-------------------------------------------------------------------------
*/
#include "postgres.h"
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
new file mode 100644
index 00000000000..31f57c30479
--- /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 4th 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 dbc557e5838..2459adcf9fd 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 04bd9b95b27..bb9a5446861 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 0251664e4a1..da0228de6bb 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -372,6 +372,16 @@ DATA(insert ( 1984 829 829 3 s 1220 403 0 ));
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 f1a52ce3e0a..a87ec423e1c 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 80a40ab1284..ce8dc59e5af 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -303,6 +303,12 @@ DATA(insert ( 718 600 1416 e f ));
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
*/
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0cde14c25dc..5819d5309f1 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 45feb69b93c..fe8795ac8bf 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 bd673fe59ba..546527aa8e3 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 ec4aedb8516..3d5d8660718 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 6e4c65e6ad3..9f61238179b 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 b4d7359f19e..7dc179e2556 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -101,6 +101,21 @@ typedef struct macaddr
unsigned char f;
} 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
*/
@@ -111,12 +126,19 @@ typedef struct macaddr
/* obsolescent variants */
#define DatumGetInetP(X) ((inet *) PG_DETOAST_DATUM(X))
#define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n))
+
/* 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 00000000000..74f53a121f2
--- /dev/null
+++ b/src/test/regress/expected/macaddr8.out
@@ -0,0 +1,354 @@
+--
+-- 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);
+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 0bcec136c53..64d9dd605fd 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 9f38349e90f..ea7b5b4aa26 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 2987b24ebb4..cf48ea7cc8d 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 00000000000..57a227c5ab7
--- /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;