Add support for EUI-64 MAC addresses as macaddr8
authorStephen Frost <sfrost@snowman.net>
Wed, 15 Mar 2017 15:16:25 +0000 (11:16 -0400)
committerStephen Frost <sfrost@snowman.net>
Wed, 15 Mar 2017 15:16:25 +0000 (11:16 -0400)
This adds in support for EUI-64 MAC addresses by adding a new data type
called 'macaddr8' (using our usual convention of indicating the number
of bytes stored).

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

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

Discussion: https://postgr.es/m/CAJrrPGcUi8ZH+KkK+=TctNQ+EfkeCEHtMU_yo1mvX8hsk_ghNQ@mail.gmail.com

37 files changed:
contrib/btree_gin/Makefile
contrib/btree_gin/btree_gin--1.0--1.1.sql [new file with mode: 0644]
contrib/btree_gin/btree_gin.c
contrib/btree_gin/btree_gin.control
contrib/btree_gin/expected/macaddr8.out [new file with mode: 0644]
contrib/btree_gin/sql/macaddr8.sql [new file with mode: 0644]
contrib/btree_gist/Makefile
contrib/btree_gist/btree_gist--1.3--1.4.sql [new file with mode: 0644]
contrib/btree_gist/btree_gist.control
contrib/btree_gist/btree_gist.h
contrib/btree_gist/btree_macaddr8.c [new file with mode: 0644]
contrib/btree_gist/expected/macaddr8.out [new file with mode: 0644]
contrib/btree_gist/sql/macaddr8.sql [new file with mode: 0644]
doc/src/sgml/brin.sgml
doc/src/sgml/btree-gin.sgml
doc/src/sgml/btree-gist.sgml
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
src/backend/utils/adt/Makefile
src/backend/utils/adt/mac.c
src/backend/utils/adt/mac8.c [new file with mode: 0644]
src/backend/utils/adt/network.c
src/backend/utils/adt/selfuncs.c
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_opfamily.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/utils/inet.h
src/test/regress/expected/macaddr8.out [new file with mode: 0644]
src/test/regress/expected/opr_sanity.out
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/macaddr8.sql [new file with mode: 0644]

index 0492091599ef49c482e660bbd92d606c26144755..f22e4af7dfb2105b1d17fed6066264447d627ef1 100644 (file)
@@ -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 (file)
index 0000000..dd81d27
--- /dev/null
@@ -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;
index 030b61097f654c925d751c7e8be3d00427f4a16b..725456e940444602f316a0f5bd68aee977feb264 100644 (file)
@@ -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)
 {
index 3b2cb2d709d0adbaac4c0c604d8ba178c02fde3f..d96436e8ec422ee453c03014263451319a9200e2 100644 (file)
@@ -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 (file)
index 0000000..025b0c1
--- /dev/null
@@ -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 (file)
index 0000000..86785c3
--- /dev/null
@@ -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;
index d36f51795d0943a981df2a8ee6b4e0a1fc0ca2c0..c70f17869a2ab482e664b859f136ad5abc03d803 100644 (file)
@@ -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 (file)
index 0000000..f77f6c8
--- /dev/null
@@ -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);
index ddbf83dc32fef2e1ef6d88ebbd03a455bb20d8e1..fdf0e6ad9eedc11905f89bcd168ab39d6ea18f08 100644 (file)
@@ -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
index 9b3e22c4692dabdc16cbda245622ad348dcbc984..f759299bb2da407b22b4226572ff7b92f72a17ae 100644 (file)
@@ -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 (file)
index 0000000..13238ef
--- /dev/null
@@ -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 (file)
index 0000000..e5ec6a5
--- /dev/null
@@ -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 (file)
index 0000000..61e7d7a
--- /dev/null
@@ -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;
index 6448b18e4656ab3a140b1186d782282c1aa34f77..5bf11dc2d15b2923fabca4078bbd792718224002 100644 (file)
       <literal>&gt;</literal>
      </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>
index 2b081db9d5ab3c5943c6a0e7ba35ddde9197652e..0de8eb5c309f66f763314ee66962452d508b42ab 100644 (file)
@@ -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>
index d08647ce05a49493debdb08a15abadbeb9481836..cfdd5be84afccdf202630e8b20954f3e7f3593ab 100644 (file)
@@ -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>
index 35610307d9a4b0c4ba98971555620b9f67e57a7e..e2f8dee7b6691f119a290bd1b572f6ab17a29414 100644 (file)
        <entry>MAC (Media Access Control) address</entry>
       </row>
 
+      <row>
+       <entry><type>macaddr8</type></entry>
+       <entry></entry>
+       <entry>MAC (Media Access Control) address (EUI-64 format)</entry>
+      </row>
+
       <row>
        <entry><type>money</type></entry>
        <entry></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
+     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 <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 <literal>':'</>, <literal>'-'</> or <literal>'.'</>, 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:
+
+     <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.
+
+     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 <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>
+
+   </sect2>
+
   </sect1>
 
   <sect1 id="datatype-bit">
index 583b3b241aba0d6cf8d104db1652cf8f2fbadb91..a521912317b36faa8358e52f468efc92416714ff 100644 (file)
@@ -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>
 
 
index 0f512753e496fd57f26b2855041585c13b48b799..1fb018416ef2357bcce25b78e3ef9b80add239c1 100644 (file)
@@ -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 \
index 2270b223eab9f18f9ff47d5626c9d6a664aa279c..a1e9c53b730dca55f3077b6ebcedc5a3f5937e1d 100644 (file)
@@ -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 (file)
index 0000000..31f57c3
--- /dev/null
@@ -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);
+}
index dbc557e583852802be5e8ed26cfd170cbeb6f844..2459adcf9fdaddd088ef7f7f3dfed56597ebcdcd 100644 (file)
@@ -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;
+           }
    }
 
    /*
index 04bd9b95b27db9a40fae8b9413085f2752d510f4..bb9a5446861bde72e1caee147ef7e0c382b8de16 100644 (file)
@@ -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);
index 0251664e4a1f504a7c204a04f24eaba1bd32b862..da0228de6bb69b9f34934338c307885036deb66d 100644 (file)
@@ -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 ));
index f1a52ce3e0a6eacdfb6f3060af884cfc2b40fb64..a87ec423e1cb8fc199f2d25b18efc483f5121f83 100644 (file)
@@ -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 ));
index 80a40ab12842f7feced9ab23b6406d3672c5ec27..ce8dc59e5af709bc01c5c16fe0657fd66b719dc0 100644 (file)
@@ -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
  */
index 0cde14c25dccce2febe90788debccc46595ebf51..5819d5309f1a94c5d91c427cf5e888a40fdee6e0 100644 (file)
@@ -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 ));
index 45feb69b93caec3372d57fdf0f2297d22897c92a..fe8795ac8bf3f88a86ef4c138d8341fa7514192a 100644 (file)
@@ -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");
index bd673fe59bae1426f60d622cddbe127ffc367725..546527aa8e321ade657f9debf91975d893dc1b41 100644 (file)
@@ -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 ));
index ec4aedb8516e84b7821612fc7d5deac8bd7bedca..3d5d8660718a7311e9ab3dc6b536f8936c1e6a06 100644 (file)
@@ -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_ ));
index 6e4c65e6ad3267a2257a91d9b956542b1ae8ff44..9f61238179bf766aae54390646b38e1c09bc77e5 100644 (file)
@@ -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_ ));
index b4d7359f19e95d6a24a4aa7a990d203016f61634..7dc179e2556e7dea7618b0286cd325d15cfcea62 100644 (file)
@@ -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 (file)
index 0000000..74f53a1
--- /dev/null
@@ -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;
index 0bcec136c53784cf3729f44fafc351606c67bccc..64d9dd605fdc4c90b6f191705156ca327eb327d4 100644 (file)
@@ -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
index 9f38349e90f1ae12753ebe7e2ca1652ae8765a7d..ea7b5b4aa26c6e82e653a11a671f8096a7fce4bb 100644 (file)
@@ -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
index 2987b24ebb48e5e23915ca07f41551e4c49517ce..cf48ea7cc8d3d207513205e2eeef6bc372f6601b 100644 (file)
@@ -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 (file)
index 0000000..57a227c
--- /dev/null
@@ -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;