Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * mac.c
4 : * PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
5 : *
6 : * Portions Copyright (c) 1998-2023, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/backend/utils/adt/mac.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 :
14 : #include "postgres.h"
15 :
16 : #include "common/hashfn.h"
17 : #include "lib/hyperloglog.h"
18 : #include "libpq/pqformat.h"
19 : #include "port/pg_bswap.h"
20 : #include "utils/builtins.h"
21 : #include "utils/guc.h"
22 : #include "utils/inet.h"
23 : #include "utils/sortsupport.h"
24 :
25 :
26 : /*
27 : * Utility macros used for sorting and comparing:
28 : */
29 :
30 : #define hibits(addr) \
31 : ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
32 :
33 : #define lobits(addr) \
34 : ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
35 :
36 : /* sortsupport for macaddr */
37 : typedef struct
38 : {
39 : int64 input_count; /* number of non-null values seen */
40 : bool estimating; /* true if estimating cardinality */
41 :
42 : hyperLogLogState abbr_card; /* cardinality estimator */
43 : } macaddr_sortsupport_state;
44 :
45 : static int macaddr_cmp_internal(macaddr *a1, macaddr *a2);
46 : static int macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup);
47 : static bool macaddr_abbrev_abort(int memtupcount, SortSupport ssup);
48 : static Datum macaddr_abbrev_convert(Datum original, SortSupport ssup);
49 :
50 : /*
51 : * MAC address reader. Accepts several common notations.
52 : */
53 :
54 : Datum
8284 tgl 55 CBC 1864 : macaddr_in(PG_FUNCTION_ARGS)
56 : {
57 1864 : char *str = PG_GETARG_CSTRING(0);
116 tgl 58 GNC 1864 : Node *escontext = fcinfo->context;
7901 tgl 59 ECB : macaddr *result;
60 : int a,
61 : b,
62 : c,
63 : d,
64 : e,
65 : f;
66 : char junk[2];
67 : int count;
68 :
69 : /* %1s matches iff there is trailing non-whitespace garbage */
70 :
7483 tgl 71 GIC 1864 : count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
7483 tgl 72 ECB : &a, &b, &c, &d, &e, &f, junk);
7901 tgl 73 GIC 1864 : if (count != 6)
7483 tgl 74 CBC 36 : count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
7483 tgl 75 ECB : &a, &b, &c, &d, &e, &f, junk);
7901 tgl 76 GIC 1864 : if (count != 6)
7483 tgl 77 CBC 33 : count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
7483 tgl 78 ECB : &a, &b, &c, &d, &e, &f, junk);
7901 tgl 79 GIC 1864 : if (count != 6)
7483 tgl 80 CBC 30 : count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
7483 tgl 81 ECB : &a, &b, &c, &d, &e, &f, junk);
7901 tgl 82 GIC 1864 : if (count != 6)
7483 tgl 83 CBC 27 : count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
7483 tgl 84 ECB : &a, &b, &c, &d, &e, &f, junk);
3092 peter_e 85 GIC 1864 : if (count != 6)
3092 peter_e 86 CBC 24 : count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
3092 peter_e 87 ECB : &a, &b, &c, &d, &e, &f, junk);
7603 bruce 88 GIC 1864 : if (count != 6)
7483 tgl 89 CBC 21 : count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
7483 tgl 90 ECB : &a, &b, &c, &d, &e, &f, junk);
7901 tgl 91 GIC 1864 : if (count != 6)
116 tgl 92 GNC 18 : ereturn(escontext, (Datum) 0,
7196 tgl 93 ECB : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
94 : errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
95 : str)));
96 :
7901 tgl 97 GIC 1846 : if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
7901 tgl 98 CBC 1846 : (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
99 1846 : (e < 0) || (e > 255) || (f < 0) || (f > 255))
116 tgl 100 UNC 0 : ereturn(escontext, (Datum) 0,
7196 tgl 101 EUB : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
102 : errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
103 :
8954 bruce 104 GIC 1846 : result = (macaddr *) palloc(sizeof(macaddr));
8954 bruce 105 ECB :
8954 bruce 106 GIC 1846 : result->a = a;
8954 bruce 107 CBC 1846 : result->b = b;
108 1846 : result->c = c;
109 1846 : result->d = d;
110 1846 : result->e = e;
111 1846 : result->f = f;
8954 bruce 112 ECB :
8284 tgl 113 GIC 1846 : PG_RETURN_MACADDR_P(result);
8954 bruce 114 ECB : }
115 :
116 : /*
117 : * MAC address output function. Fixed format.
118 : */
119 :
120 : Datum
8284 tgl 121 GIC 1604 : macaddr_out(PG_FUNCTION_ARGS)
8954 bruce 122 ECB : {
8053 bruce 123 GIC 1604 : macaddr *addr = PG_GETARG_MACADDR_P(0);
8954 bruce 124 ECB : char *result;
125 :
8954 bruce 126 GIC 1604 : result = (char *) palloc(32);
8954 bruce 127 ECB :
7529 bruce 128 GIC 1604 : snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
7522 bruce 129 CBC 1604 : addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
8284 tgl 130 ECB :
8284 tgl 131 GIC 1604 : PG_RETURN_CSTRING(result);
8954 bruce 132 ECB : }
133 :
134 : /*
135 : * macaddr_recv - converts external binary format to macaddr
136 : *
137 : * The external representation is just the six bytes, MSB first.
138 : */
139 : Datum
7271 tgl 140 UIC 0 : macaddr_recv(PG_FUNCTION_ARGS)
7271 tgl 141 EUB : {
7271 tgl 142 UIC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
7188 bruce 143 EUB : macaddr *addr;
144 :
7271 tgl 145 UIC 0 : addr = (macaddr *) palloc(sizeof(macaddr));
7271 tgl 146 EUB :
7271 tgl 147 UIC 0 : addr->a = pq_getmsgbyte(buf);
7271 tgl 148 UBC 0 : addr->b = pq_getmsgbyte(buf);
149 0 : addr->c = pq_getmsgbyte(buf);
150 0 : addr->d = pq_getmsgbyte(buf);
151 0 : addr->e = pq_getmsgbyte(buf);
152 0 : addr->f = pq_getmsgbyte(buf);
7271 tgl 153 EUB :
7271 tgl 154 UIC 0 : PG_RETURN_MACADDR_P(addr);
7271 tgl 155 EUB : }
156 :
157 : /*
158 : * macaddr_send - converts macaddr to binary format
159 : */
160 : Datum
7271 tgl 161 UIC 0 : macaddr_send(PG_FUNCTION_ARGS)
7271 tgl 162 EUB : {
7188 bruce 163 UIC 0 : macaddr *addr = PG_GETARG_MACADDR_P(0);
7271 tgl 164 EUB : StringInfoData buf;
165 :
7271 tgl 166 UIC 0 : pq_begintypsend(&buf);
7271 tgl 167 UBC 0 : pq_sendbyte(&buf, addr->a);
168 0 : pq_sendbyte(&buf, addr->b);
169 0 : pq_sendbyte(&buf, addr->c);
170 0 : pq_sendbyte(&buf, addr->d);
171 0 : pq_sendbyte(&buf, addr->e);
172 0 : pq_sendbyte(&buf, addr->f);
173 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
7271 tgl 174 EUB : }
175 :
176 :
177 : /*
178 : * Comparison function for sorting:
179 : */
180 :
181 : static int
8284 tgl 182 GIC 102142 : macaddr_cmp_internal(macaddr *a1, macaddr *a2)
8954 bruce 183 ECB : {
8284 tgl 184 GIC 102142 : if (hibits(a1) < hibits(a2))
8284 tgl 185 CBC 47702 : return -1;
186 54440 : else if (hibits(a1) > hibits(a2))
187 48045 : return 1;
188 6395 : else if (lobits(a1) < lobits(a2))
189 29 : return -1;
190 6366 : else if (lobits(a1) > lobits(a2))
191 25 : return 1;
8284 tgl 192 ECB : else
8284 tgl 193 GIC 6341 : return 0;
8931 tgl 194 ECB : }
195 :
196 : Datum
8284 tgl 197 GIC 6639 : macaddr_cmp(PG_FUNCTION_ARGS)
8954 bruce 198 ECB : {
8053 bruce 199 GIC 6639 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 200 CBC 6639 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 201 ECB :
8284 tgl 202 GIC 6639 : PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
8931 tgl 203 ECB : }
204 :
205 : /*
206 : * Boolean comparisons.
207 : */
208 :
209 : Datum
8284 tgl 210 GIC 70568 : macaddr_lt(PG_FUNCTION_ARGS)
8954 bruce 211 ECB : {
8053 bruce 212 GIC 70568 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 213 CBC 70568 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 214 ECB :
8284 tgl 215 GIC 70568 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
8931 tgl 216 ECB : }
217 :
218 : Datum
8284 tgl 219 GIC 3118 : macaddr_le(PG_FUNCTION_ARGS)
8954 bruce 220 ECB : {
8053 bruce 221 GIC 3118 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 222 CBC 3118 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 223 ECB :
8284 tgl 224 GIC 3118 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
8931 tgl 225 ECB : }
226 :
227 : Datum
8284 tgl 228 GIC 14669 : macaddr_eq(PG_FUNCTION_ARGS)
8954 bruce 229 ECB : {
8053 bruce 230 GIC 14669 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 231 CBC 14669 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 232 ECB :
8284 tgl 233 GIC 14669 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
8931 tgl 234 ECB : }
235 :
236 : Datum
8284 tgl 237 GIC 2458 : macaddr_ge(PG_FUNCTION_ARGS)
8954 bruce 238 ECB : {
8053 bruce 239 GIC 2458 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 240 CBC 2458 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 241 ECB :
8284 tgl 242 GIC 2458 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
8931 tgl 243 ECB : }
244 :
245 : Datum
8284 tgl 246 GIC 4516 : macaddr_gt(PG_FUNCTION_ARGS)
8284 tgl 247 ECB : {
8053 bruce 248 GIC 4516 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 249 CBC 4516 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 250 ECB :
8284 tgl 251 GIC 4516 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
8284 tgl 252 ECB : }
253 :
254 : Datum
8284 tgl 255 GIC 12 : macaddr_ne(PG_FUNCTION_ARGS)
8954 bruce 256 ECB : {
8053 bruce 257 GIC 12 : macaddr *a1 = PG_GETARG_MACADDR_P(0);
8053 bruce 258 CBC 12 : macaddr *a2 = PG_GETARG_MACADDR_P(1);
8284 tgl 259 ECB :
8284 tgl 260 GIC 12 : PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
8954 bruce 261 ECB : }
262 :
263 : /*
264 : * Support function for hash indexes on macaddr.
265 : */
266 : Datum
8157 tgl 267 GIC 1167 : hashmacaddr(PG_FUNCTION_ARGS)
8157 tgl 268 ECB : {
8053 bruce 269 GIC 1167 : macaddr *key = PG_GETARG_MACADDR_P(0);
8157 tgl 270 ECB :
7701 tgl 271 GIC 1167 : return hash_any((unsigned char *) key, sizeof(macaddr));
8157 tgl 272 ECB : }
273 :
274 : Datum
2047 rhaas 275 GIC 30 : hashmacaddrextended(PG_FUNCTION_ARGS)
2047 rhaas 276 ECB : {
2047 rhaas 277 GIC 30 : macaddr *key = PG_GETARG_MACADDR_P(0);
2047 rhaas 278 ECB :
2047 rhaas 279 GIC 30 : return hash_any_extended((unsigned char *) key, sizeof(macaddr),
2047 rhaas 280 CBC 30 : PG_GETARG_INT64(1));
2047 rhaas 281 ECB : }
282 :
283 : /*
284 : * Arithmetic functions: bitwise NOT, AND, OR.
285 : */
286 : Datum
4098 rhaas 287 GIC 36 : macaddr_not(PG_FUNCTION_ARGS)
4098 rhaas 288 ECB : {
3955 bruce 289 GIC 36 : macaddr *addr = PG_GETARG_MACADDR_P(0);
3955 bruce 290 ECB : macaddr *result;
291 :
4098 rhaas 292 GIC 36 : result = (macaddr *) palloc(sizeof(macaddr));
4098 rhaas 293 CBC 36 : result->a = ~addr->a;
294 36 : result->b = ~addr->b;
295 36 : result->c = ~addr->c;
296 36 : result->d = ~addr->d;
297 36 : result->e = ~addr->e;
298 36 : result->f = ~addr->f;
299 36 : PG_RETURN_MACADDR_P(result);
4098 rhaas 300 ECB : }
301 :
302 : Datum
4098 rhaas 303 GIC 36 : macaddr_and(PG_FUNCTION_ARGS)
4098 rhaas 304 ECB : {
3955 bruce 305 GIC 36 : macaddr *addr1 = PG_GETARG_MACADDR_P(0);
3955 bruce 306 CBC 36 : macaddr *addr2 = PG_GETARG_MACADDR_P(1);
3955 bruce 307 ECB : macaddr *result;
308 :
4098 rhaas 309 GIC 36 : result = (macaddr *) palloc(sizeof(macaddr));
4098 rhaas 310 CBC 36 : result->a = addr1->a & addr2->a;
311 36 : result->b = addr1->b & addr2->b;
312 36 : result->c = addr1->c & addr2->c;
313 36 : result->d = addr1->d & addr2->d;
314 36 : result->e = addr1->e & addr2->e;
315 36 : result->f = addr1->f & addr2->f;
316 36 : PG_RETURN_MACADDR_P(result);
4098 rhaas 317 ECB : }
318 :
319 : Datum
4098 rhaas 320 GIC 36 : macaddr_or(PG_FUNCTION_ARGS)
4098 rhaas 321 ECB : {
3955 bruce 322 GIC 36 : macaddr *addr1 = PG_GETARG_MACADDR_P(0);
3955 bruce 323 CBC 36 : macaddr *addr2 = PG_GETARG_MACADDR_P(1);
3955 bruce 324 ECB : macaddr *result;
325 :
4098 rhaas 326 GIC 36 : result = (macaddr *) palloc(sizeof(macaddr));
4098 rhaas 327 CBC 36 : result->a = addr1->a | addr2->a;
328 36 : result->b = addr1->b | addr2->b;
329 36 : result->c = addr1->c | addr2->c;
330 36 : result->d = addr1->d | addr2->d;
331 36 : result->e = addr1->e | addr2->e;
332 36 : result->f = addr1->f | addr2->f;
333 36 : PG_RETURN_MACADDR_P(result);
4098 rhaas 334 ECB : }
335 :
336 : /*
337 : * Truncation function to allow comparing mac manufacturers.
338 : * From suggestion by Alex Pilosov <alex@pilosoft.com>
339 : */
340 : Datum
8264 lockhart 341 GIC 36 : macaddr_trunc(PG_FUNCTION_ARGS)
8954 bruce 342 ECB : {
8053 bruce 343 GIC 36 : macaddr *addr = PG_GETARG_MACADDR_P(0);
7901 tgl 344 ECB : macaddr *result;
345 :
8264 lockhart 346 GIC 36 : result = (macaddr *) palloc(sizeof(macaddr));
8264 lockhart 347 ECB :
8264 lockhart 348 GIC 36 : result->a = addr->a;
8264 lockhart 349 CBC 36 : result->b = addr->b;
350 36 : result->c = addr->c;
351 36 : result->d = 0;
352 36 : result->e = 0;
353 36 : result->f = 0;
8264 lockhart 354 ECB :
8264 lockhart 355 GIC 36 : PG_RETURN_MACADDR_P(result);
8954 bruce 356 ECB : }
357 :
358 : /*
359 : * SortSupport strategy function. Populates a SortSupport struct with the
360 : * information necessary to use comparison by abbreviated keys.
361 : */
362 : Datum
2202 teodor 363 GIC 10 : macaddr_sortsupport(PG_FUNCTION_ARGS)
2202 teodor 364 ECB : {
2202 teodor 365 GIC 10 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
2202 teodor 366 ECB :
2202 teodor 367 GIC 10 : ssup->comparator = macaddr_fast_cmp;
2202 teodor 368 CBC 10 : ssup->ssup_extra = NULL;
2202 teodor 369 ECB :
2202 teodor 370 GIC 10 : if (ssup->abbreviate)
2202 teodor 371 ECB : {
372 : macaddr_sortsupport_state *uss;
373 : MemoryContext oldcontext;
374 :
2202 teodor 375 GIC 10 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
2202 teodor 376 ECB :
2202 teodor 377 GIC 10 : uss = palloc(sizeof(macaddr_sortsupport_state));
2202 teodor 378 CBC 10 : uss->input_count = 0;
379 10 : uss->estimating = true;
380 10 : initHyperLogLog(&uss->abbr_card, 10);
2202 teodor 381 ECB :
2202 teodor 382 GIC 10 : ssup->ssup_extra = uss;
2202 teodor 383 ECB :
372 john.naylor 384 GIC 10 : ssup->comparator = ssup_datum_unsigned_cmp;
2202 teodor 385 CBC 10 : ssup->abbrev_converter = macaddr_abbrev_convert;
386 10 : ssup->abbrev_abort = macaddr_abbrev_abort;
387 10 : ssup->abbrev_full_comparator = macaddr_fast_cmp;
2202 teodor 388 ECB :
2202 teodor 389 GIC 10 : MemoryContextSwitchTo(oldcontext);
2202 teodor 390 ECB : }
391 :
2202 teodor 392 GIC 10 : PG_RETURN_VOID();
2202 teodor 393 ECB : }
394 :
395 : /*
396 : * SortSupport "traditional" comparison function. Pulls two MAC addresses from
397 : * the heap and runs a standard comparison on them.
398 : */
399 : static int
2202 teodor 400 GIC 162 : macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup)
2202 teodor 401 ECB : {
2202 teodor 402 GIC 162 : macaddr *arg1 = DatumGetMacaddrP(x);
2202 teodor 403 CBC 162 : macaddr *arg2 = DatumGetMacaddrP(y);
2202 teodor 404 ECB :
2202 teodor 405 GIC 162 : return macaddr_cmp_internal(arg1, arg2);
2202 teodor 406 ECB : }
407 :
408 : /*
409 : * Callback for estimating effectiveness of abbreviated key optimization.
410 : *
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.
413 : */
414 : static bool
2202 teodor 415 GIC 6 : macaddr_abbrev_abort(int memtupcount, SortSupport ssup)
2202 teodor 416 ECB : {
2202 teodor 417 GIC 6 : macaddr_sortsupport_state *uss = ssup->ssup_extra;
2202 teodor 418 ECB : double abbr_card;
419 :
2202 teodor 420 GIC 6 : if (memtupcount < 10000 || uss->input_count < 10000 || !uss->estimating)
2202 teodor 421 CBC 6 : return false;
2202 teodor 422 ECB :
2202 teodor 423 UIC 0 : abbr_card = estimateHyperLogLog(&uss->abbr_card);
2202 teodor 424 EUB :
425 : /*
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.
430 : */
2202 teodor 431 UIC 0 : if (abbr_card > 100000.0)
2202 teodor 432 EUB : {
433 : #ifdef TRACE_SORT
2202 teodor 434 UIC 0 : if (trace_sort)
2202 teodor 435 UBC 0 : elog(LOG,
2202 teodor 436 EUB : "macaddr_abbrev: estimation ends at cardinality %f"
437 : " after " INT64_FORMAT " values (%d rows)",
438 : abbr_card, uss->input_count, memtupcount);
439 : #endif
2202 teodor 440 UIC 0 : uss->estimating = false;
2202 teodor 441 UBC 0 : return false;
2202 teodor 442 EUB : }
443 :
444 : /*
445 : * Target minimum cardinality is 1 per ~2k of non-null inputs. 0.5 row
446 : * fudge factor allows us to abort earlier on genuinely pathological data
447 : * where we've had exactly one abbreviated value in the first 2k
448 : * (non-null) rows.
449 : */
2202 teodor 450 UIC 0 : if (abbr_card < uss->input_count / 2000.0 + 0.5)
2202 teodor 451 EUB : {
452 : #ifdef TRACE_SORT
2202 teodor 453 UIC 0 : if (trace_sort)
2202 teodor 454 UBC 0 : elog(LOG,
2202 teodor 455 EUB : "macaddr_abbrev: aborting abbreviation at cardinality %f"
456 : " below threshold %f after " INT64_FORMAT " values (%d rows)",
457 : abbr_card, uss->input_count / 2000.0 + 0.5, uss->input_count,
458 : memtupcount);
459 : #endif
2202 teodor 460 UIC 0 : return true;
2202 teodor 461 EUB : }
462 :
463 : #ifdef TRACE_SORT
2202 teodor 464 UIC 0 : if (trace_sort)
2202 teodor 465 UBC 0 : elog(LOG,
2202 teodor 466 EUB : "macaddr_abbrev: cardinality %f after " INT64_FORMAT
467 : " values (%d rows)", abbr_card, uss->input_count, memtupcount);
468 : #endif
469 :
2202 teodor 470 UIC 0 : return false;
2202 teodor 471 EUB : }
472 :
473 : /*
474 : * SortSupport conversion routine. Converts original macaddr representation
475 : * to abbreviated key representation.
476 : *
477 : * Packs the bytes of a 6-byte MAC address into a Datum and treats it as an
478 : * unsigned integer for purposes of comparison. On a 64-bit machine, there
479 : * will be two zeroed bytes of padding. The integer is converted to native
480 : * endianness to facilitate easy comparison.
481 : */
482 : static Datum
2202 teodor 483 GIC 84 : macaddr_abbrev_convert(Datum original, SortSupport ssup)
2202 teodor 484 ECB : {
2202 teodor 485 GIC 84 : macaddr_sortsupport_state *uss = ssup->ssup_extra;
2202 teodor 486 CBC 84 : macaddr *authoritative = DatumGetMacaddrP(original);
2202 teodor 487 ECB : Datum res;
488 :
489 : /*
490 : * On a 64-bit machine, zero out the 8-byte datum and copy the 6 bytes of
491 : * the MAC address in. There will be two bytes of zero padding on the end
492 : * of the least significant bits.
493 : */
494 : #if SIZEOF_DATUM == 8
2202 teodor 495 GIC 84 : memset(&res, 0, SIZEOF_DATUM);
2202 teodor 496 CBC 84 : memcpy(&res, authoritative, sizeof(macaddr));
2202 teodor 497 ECB : #else /* SIZEOF_DATUM != 8 */
498 : memcpy(&res, authoritative, SIZEOF_DATUM);
499 : #endif
2202 teodor 500 GIC 84 : uss->input_count += 1;
2202 teodor 501 ECB :
502 : /*
503 : * Cardinality estimation. The estimate uses uint32, so on a 64-bit
504 : * architecture, XOR the two 32-bit halves together to produce slightly
505 : * more entropy. The two zeroed bytes won't have any practical impact on
506 : * this operation.
507 : */
2202 teodor 508 GIC 84 : if (uss->estimating)
2202 teodor 509 ECB : {
510 : uint32 tmp;
511 :
512 : #if SIZEOF_DATUM == 8
2202 teodor 513 GIC 84 : tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
2202 teodor 514 ECB : #else /* SIZEOF_DATUM != 8 */
515 : tmp = (uint32) res;
516 : #endif
517 :
2202 teodor 518 GIC 84 : addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
2202 teodor 519 ECB : }
520 :
521 : /*
522 : * Byteswap on little-endian machines.
523 : *
524 : * This is needed so that ssup_datum_unsigned_cmp() (an unsigned integer
525 : * 3-way comparator) works correctly on all platforms. Without this, the
526 : * comparator would have to call memcmp() with a pair of pointers to the
527 : * first byte of each abbreviated key, which is slower.
528 : */
2202 teodor 529 GIC 84 : res = DatumBigEndianToNative(res);
2202 teodor 530 ECB :
2202 teodor 531 GIC 84 : return res;
2202 teodor 532 ECB : }
|