2017-03-15 11:16:25 -04:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2019-01-02 12:44:25 -05:00
|
|
|
* Portions Copyright (c) 1998-2019, PostgreSQL Global Development Group
|
2017-03-15 11:16:25 -04:00
|
|
|
*
|
|
|
|
* 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)))
|
|
|
|
|
2017-03-16 00:13:37 -04:00
|
|
|
static unsigned char hex2_to_uchar(const unsigned char *str, const unsigned char *ptr);
|
2017-03-15 11:16:25 -04:00
|
|
|
|
2017-03-16 00:13:37 -04:00
|
|
|
static const signed char hexlookup[128] = {
|
2017-03-15 11:16:25 -04:00
|
|
|
-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,
|
|
|
|
};
|
|
|
|
|
2017-03-15 23:23:28 -04:00
|
|
|
/*
|
|
|
|
* hex2_to_uchar - convert 2 hex digits to a byte (unsigned char)
|
|
|
|
*
|
|
|
|
* This will ereport() if the end of the string is reached ('\0' found), or if
|
|
|
|
* either character is not a valid hex digit.
|
|
|
|
*
|
|
|
|
* ptr is the pointer to where the digits to convert are in the string, str is
|
|
|
|
* the entire string, which is used only for error reporting.
|
|
|
|
*/
|
2017-03-15 11:16:25 -04:00
|
|
|
static inline unsigned char
|
2017-03-16 00:13:37 -04:00
|
|
|
hex2_to_uchar(const unsigned char *ptr, const unsigned char *str)
|
2017-03-15 11:16:25 -04:00
|
|
|
{
|
|
|
|
unsigned char ret = 0;
|
2017-03-16 00:13:37 -04:00
|
|
|
signed char lookup;
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
/* Handle the first character */
|
2017-03-16 00:13:37 -04:00
|
|
|
if (*ptr > 127)
|
2017-03-15 11:16:25 -04:00
|
|
|
goto invalid_input;
|
|
|
|
|
2017-03-16 00:13:37 -04:00
|
|
|
lookup = hexlookup[*ptr];
|
2017-03-15 23:23:28 -04:00
|
|
|
if (lookup < 0)
|
2017-03-15 11:16:25 -04:00
|
|
|
goto invalid_input;
|
|
|
|
|
|
|
|
ret = lookup << 4;
|
|
|
|
|
|
|
|
/* Move to the second character */
|
|
|
|
ptr++;
|
|
|
|
|
2017-03-16 00:13:37 -04:00
|
|
|
if (*ptr > 127)
|
2017-03-15 11:16:25 -04:00
|
|
|
goto invalid_input;
|
|
|
|
|
2017-03-16 00:13:37 -04:00
|
|
|
lookup = hexlookup[*ptr];
|
2017-03-15 23:23:28 -04:00
|
|
|
if (lookup < 0)
|
2017-03-15 11:16:25 -04:00
|
|
|
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)
|
|
|
|
{
|
2017-05-17 16:31:56 -04:00
|
|
|
const unsigned char *str = (unsigned char *) PG_GETARG_CSTRING(0);
|
2017-03-16 00:13:37 -04:00
|
|
|
const unsigned char *ptr = str;
|
2017-03-15 11:16:25 -04:00
|
|
|
macaddr8 *result;
|
|
|
|
unsigned char a = 0,
|
|
|
|
b = 0,
|
|
|
|
c = 0,
|
|
|
|
d = 0,
|
|
|
|
e = 0,
|
|
|
|
f = 0,
|
|
|
|
g = 0,
|
|
|
|
h = 0;
|
|
|
|
int count = 0;
|
2017-03-16 00:13:37 -04:00
|
|
|
unsigned char spacer = '\0';
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
/* skip leading spaces */
|
2017-03-16 00:13:37 -04:00
|
|
|
while (*ptr && isspace(*ptr))
|
2017-03-15 11:16:25 -04:00
|
|
|
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:
|
2017-03-15 23:23:28 -04:00
|
|
|
a = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 2:
|
2017-03-15 23:23:28 -04:00
|
|
|
b = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 3:
|
2017-03-15 23:23:28 -04:00
|
|
|
c = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 4:
|
2017-03-15 23:23:28 -04:00
|
|
|
d = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 5:
|
2017-03-15 23:23:28 -04:00
|
|
|
e = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 6:
|
2017-03-15 23:23:28 -04:00
|
|
|
f = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 7:
|
2017-03-15 23:23:28 -04:00
|
|
|
g = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
case 8:
|
2017-03-15 23:23:28 -04:00
|
|
|
h = hex2_to_uchar(ptr, str);
|
2017-03-15 11:16:25 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* must be trailing garbage... */
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 15:35:54 -04:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
|
|
|
|
str)));
|
2017-03-15 11:16:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 15:35:54 -04:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
|
|
|
|
str)));
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
/* move past the spacer */
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allow trailing whitespace after if we have 6 or 8 bytes */
|
|
|
|
if (count == 6 || count == 8)
|
|
|
|
{
|
2017-03-16 00:13:37 -04:00
|
|
|
if (isspace(*ptr))
|
2017-03-15 11:16:25 -04:00
|
|
|
{
|
2017-03-16 00:13:37 -04:00
|
|
|
while (*++ptr && isspace(*ptr));
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
/* 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),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 15:35:54 -04:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
|
|
|
|
str)));
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2017-08-31 22:21:21 -04:00
|
|
|
Datum
|
|
|
|
hashmacaddr8extended(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
macaddr8 *key = PG_GETARG_MACADDR8_P(0);
|
|
|
|
|
|
|
|
return hash_any_extended((unsigned char *) key, sizeof(macaddr8),
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
}
|
|
|
|
|
2017-03-15 11:16:25 -04:00
|
|
|
/*
|
|
|
|
* 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"),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 15:35:54 -04:00
|
|
|
errhint("Only addresses that have FF and FE as values in the "
|
2017-09-11 11:20:47 -04:00
|
|
|
"4th and 5th bytes from the left, for example "
|
|
|
|
"xx:xx:xx:ff:fe:xx:xx:xx, are eligible to be converted "
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 15:35:54 -04:00
|
|
|
"from macaddr8 to macaddr.")));
|
2017-03-15 11:16:25 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|