1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

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

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