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