Add support for EUI-64 MAC addresses as macaddr8

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

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

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

Discussion: https://postgr.es/m/CAJrrPGcUi8ZH+KkK+=TctNQ+EfkeCEHtMU_yo1mvX8hsk_ghNQ@mail.gmail.com
This commit is contained in:
Stephen Frost 2017-03-15 11:16:25 -04:00
parent 42bdaebf16
commit c7a9fa399d
37 changed files with 1826 additions and 20 deletions

View 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

View File

@ -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;

View 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)
{

View 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

View File

@ -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)

View File

@ -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;

View 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))

View File

@ -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);

View 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

View 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,

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -281,6 +281,17 @@
<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>

View 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>

View 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>

View File

@ -166,6 +166,12 @@
<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">

View 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>

View 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 \

View File

@ -1,7 +1,14 @@
/*
* PostgreSQL type definitions for MAC addresses.
/*-------------------------------------------------------------------------
*
* src/backend/utils/adt/mac.c
* mac.c
* PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
*
* Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/utils/adt/mac.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"

View File

@ -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);
}

View 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;
}
}
/*

View 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);

View 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 ));

View 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 ));

View 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
*/

View 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 ));

View 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");

View 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 ));

View 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_ ));

View 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_ ));

View 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
*/

View File

@ -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;

View 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

View 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

View File

@ -41,6 +41,7 @@ test: reltime
test: tinterval
test: inet
test: macaddr
test: macaddr8
test: tstypes
test: comments
test: geometry

View File

@ -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;