1/*-------------------------------------------------------------------------
4 * PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
6 * Portions Copyright (c) 1998-2025, PostgreSQL Global Development Group
9 * src/backend/utils/adt/mac.c
11 *-------------------------------------------------------------------------
20#include "utils/fmgrprotos.h"
27 * Utility macros used for sorting and comparing:
30 #define hibits(addr) \
31 ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
33 #define lobits(addr) \
34 ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
36/* sortsupport for macaddr */
51 * MAC address reader. Accepts several common notations.
58 Node *escontext = fcinfo->context;
69 /* %1s matches iff there is trailing non-whitespace garbage */
71 count = sscanf(
str,
"%x:%x:%x:%x:%x:%x%1s",
72 &
a, &
b, &
c, &d, &
e, &f, junk);
74 count = sscanf(
str,
"%x-%x-%x-%x-%x-%x%1s",
75 &
a, &
b, &
c, &d, &
e, &f, junk);
77 count = sscanf(
str,
"%2x%2x%2x:%2x%2x%2x%1s",
78 &
a, &
b, &
c, &d, &
e, &f, junk);
80 count = sscanf(
str,
"%2x%2x%2x-%2x%2x%2x%1s",
81 &
a, &
b, &
c, &d, &
e, &f, junk);
83 count = sscanf(
str,
"%2x%2x.%2x%2x.%2x%2x%1s",
84 &
a, &
b, &
c, &d, &
e, &f, junk);
86 count = sscanf(
str,
"%2x%2x-%2x%2x-%2x%2x%1s",
87 &
a, &
b, &
c, &d, &
e, &f, junk);
89 count = sscanf(
str,
"%2x%2x%2x%2x%2x%2x%1s",
90 &
a, &
b, &
c, &d, &
e, &f, junk);
93 (
errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
94 errmsg(
"invalid input syntax for type %s: \"%s\"",
"macaddr",
97 if ((
a < 0) || (
a > 255) || (
b < 0) || (
b > 255) ||
98 (
c < 0) || (
c > 255) || (d < 0) || (d > 255) ||
99 (
e < 0) || (
e > 255) || (f < 0) || (f > 255))
101 (
errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
102 errmsg(
"invalid octet value in \"macaddr\" value: \"%s\"",
str)));
117 * MAC address output function. Fixed format.
126 result = (
char *)
palloc(32);
128 snprintf(result, 32,
"%02x:%02x:%02x:%02x:%02x:%02x",
129 addr->
a, addr->
b, addr->
c, addr->
d, addr->
e, addr->
f);
135 * macaddr_recv - converts external binary format to macaddr
137 * The external representation is just the six bytes, MSB first.
158 * macaddr_send - converts macaddr to binary format
178 * Comparison function for sorting:
206 * Boolean comparisons.
264 * Support function for hash indexes on macaddr.
284 * Arithmetic functions: bitwise NOT, AND, OR.
293 result->
a = ~addr->a;
294 result->
b = ~addr->b;
295 result->
c = ~addr->c;
296 result->
d = ~addr->d;
297 result->
e = ~addr->e;
298 result->
f = ~addr->f;
310 result->
a = addr1->
a & addr2->
a;
311 result->
b = addr1->
b & addr2->
b;
312 result->
c = addr1->
c & addr2->
c;
313 result->
d = addr1->
d & addr2->
d;
314 result->
e = addr1->
e & addr2->
e;
315 result->
f = addr1->
f & addr2->
f;
327 result->
a = addr1->
a | addr2->
a;
328 result->
b = addr1->
b | addr2->
b;
329 result->
c = addr1->
c | addr2->
c;
330 result->
d = addr1->
d | addr2->
d;
331 result->
e = addr1->
e | addr2->
e;
332 result->
f = addr1->
f | addr2->
f;
337 * Truncation function to allow comparing mac manufacturers.
338 * From suggestion by Alex Pilosov <alex@pilosoft.com>
359 * SortSupport strategy function. Populates a SortSupport struct with the
360 * information necessary to use comparison by abbreviated keys.
396 * SortSupport "traditional" comparison function. Pulls two MAC addresses from
397 * the heap and runs a standard comparison on them.
409 * Callback for estimating effectiveness of abbreviated key optimization.
411 * We pay no attention to the cardinality of the non-abbreviated data, because
412 * there is no equality fast-path within authoritative macaddr comparator.
420 if (memtupcount < 10000 || uss->input_count < 10000 || !uss->estimating)
426 * If we have >100k distinct values, then even if we were sorting many
427 * billion rows we'd likely still break even, and the penalty of undoing
428 * that many rows of abbrevs would probably not be worth it. At this point
429 * we stop counting because we know that we're now fully committed.
431 if (abbr_card > 100000.0)
435 "macaddr_abbrev: estimation ends at cardinality %f"
443 * Target minimum cardinality is 1 per ~2k of non-null inputs. 0.5 row
444 * fudge factor allows us to abort earlier on genuinely pathological data
445 * where we've had exactly one abbreviated value in the first 2k
448 if (abbr_card < uss->input_count / 2000.0 + 0.5)
452 "macaddr_abbrev: aborting abbreviation at cardinality %f"
453 " below threshold %f after " INT64_FORMAT " values (%d rows)",
462 " values (%d rows)", abbr_card, uss->
input_count, memtupcount);
468 * SortSupport conversion routine. Converts original macaddr representation
469 * to abbreviated key representation.
471 * Packs the bytes of a 6-byte MAC address into a Datum and treats it as an
472 * unsigned integer for purposes of comparison. On a 64-bit machine, there
473 * will be two zeroed bytes of padding. The integer is converted to native
474 * endianness to facilitate easy comparison.
484 * Zero out the 8-byte Datum and copy in the 6 bytes of the MAC address.
485 * There will be two bytes of zero padding on the end of the least
489 "Datum is too small for macaddr");
490 memset(&res, 0,
sizeof(res));
491 memcpy(&res, authoritative,
sizeof(
macaddr));
495 * Cardinality estimation. The estimate uses uint32, so XOR the two 32-bit
496 * halves together to produce slightly more entropy. The two zeroed bytes
497 * won't have any practical impact on this operation.
509 * Byteswap on little-endian machines.
511 * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
512 * 3-way comparator) works correctly on all platforms. Without this, the
513 * comparator would have to call memcmp() with a pair of pointers to the
514 * first byte of each abbreviated key, which is slower.
#define StaticAssertStmt(condition, errmessage)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereturn(context, dummy_value,...)
#define PG_RETURN_BYTEA_P(x)
#define PG_GETARG_POINTER(n)
#define PG_RETURN_CSTRING(x)
#define PG_GETARG_CSTRING(n)
#define PG_GETARG_INT64(n)
#define PG_RETURN_INT32(x)
#define PG_RETURN_BOOL(x)
static Datum hash_uint32(uint32 k)
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
static Datum hash_any(const unsigned char *k, int keylen)
static const FormData_pg_attribute a1
static const FormData_pg_attribute a2
void initHyperLogLog(hyperLogLogState *cState, uint8 bwidth)
double estimateHyperLogLog(hyperLogLogState *cState)
void addHyperLogLog(hyperLogLogState *cState, uint32 hash)
Datum macaddr_lt(PG_FUNCTION_ARGS)
Datum macaddr_cmp(PG_FUNCTION_ARGS)
static int macaddr_cmp_internal(macaddr *a1, macaddr *a2)
Datum hashmacaddrextended(PG_FUNCTION_ARGS)
Datum hashmacaddr(PG_FUNCTION_ARGS)
static Datum macaddr_abbrev_convert(Datum original, SortSupport ssup)
Datum macaddr_or(PG_FUNCTION_ARGS)
Datum macaddr_recv(PG_FUNCTION_ARGS)
Datum macaddr_ne(PG_FUNCTION_ARGS)
Datum macaddr_trunc(PG_FUNCTION_ARGS)
Datum macaddr_eq(PG_FUNCTION_ARGS)
Datum macaddr_in(PG_FUNCTION_ARGS)
Datum macaddr_not(PG_FUNCTION_ARGS)
static bool macaddr_abbrev_abort(int memtupcount, SortSupport ssup)
Datum macaddr_and(PG_FUNCTION_ARGS)
Datum macaddr_send(PG_FUNCTION_ARGS)
Datum macaddr_sortsupport(PG_FUNCTION_ARGS)
Datum macaddr_ge(PG_FUNCTION_ARGS)
static int macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup)
Datum macaddr_le(PG_FUNCTION_ARGS)
Datum macaddr_out(PG_FUNCTION_ARGS)
Datum macaddr_gt(PG_FUNCTION_ARGS)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
#define DatumBigEndianToNative(x)
static uint32 DatumGetUInt32(Datum X)
static uint64 DatumGetUInt64(Datum X)
struct SortSupportData * SortSupport
struct StringInfoData * StringInfo
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Datum(* abbrev_converter)(Datum original, SortSupport ssup)
int(* abbrev_full_comparator)(Datum x, Datum y, SortSupport ssup)
bool(* abbrev_abort)(int memtupcount, SortSupport ssup)
hyperLogLogState abbr_card
int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)
#define PG_GETARG_MACADDR_P(n)
#define PG_RETURN_MACADDR_P(x)
static macaddr * DatumGetMacaddrP(Datum X)