LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - mac.c (source / functions) Coverage Total Hit UNC UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 82.3 % 192 158 1 17 16 86 2 70 18 86 2
Current Date: 2023-04-08 15:15:32 Functions: 90.9 % 22 20 2 19 1 2 19
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      55 CBC        1864 : macaddr_in(PG_FUNCTION_ARGS)
      56                 : {
      57            1864 :     char       *str = PG_GETARG_CSTRING(0);
      58 GNC        1864 :     Node       *escontext = fcinfo->context;
      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                 : 
      71 GIC        1864 :     count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
      72 ECB             :                    &a, &b, &c, &d, &e, &f, junk);
      73 GIC        1864 :     if (count != 6)
      74 CBC          36 :         count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
      75 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      76 GIC        1864 :     if (count != 6)
      77 CBC          33 :         count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
      78 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      79 GIC        1864 :     if (count != 6)
      80 CBC          30 :         count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
      81 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      82 GIC        1864 :     if (count != 6)
      83 CBC          27 :         count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
      84 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      85 GIC        1864 :     if (count != 6)
      86 CBC          24 :         count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
      87 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      88 GIC        1864 :     if (count != 6)
      89 CBC          21 :         count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
      90 ECB             :                        &a, &b, &c, &d, &e, &f, junk);
      91 GIC        1864 :     if (count != 6)
      92 GNC          18 :         ereturn(escontext, (Datum) 0,
      93 ECB             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      94                 :                  errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
      95                 :                         str)));
      96                 : 
      97 GIC        1846 :     if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
      98 CBC        1846 :         (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
      99            1846 :         (e < 0) || (e > 255) || (f < 0) || (f > 255))
     100 UNC           0 :         ereturn(escontext, (Datum) 0,
     101 EUB             :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     102                 :                  errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
     103                 : 
     104 GIC        1846 :     result = (macaddr *) palloc(sizeof(macaddr));
     105 ECB             : 
     106 GIC        1846 :     result->a = a;
     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;
     112 ECB             : 
     113 GIC        1846 :     PG_RETURN_MACADDR_P(result);
     114 ECB             : }
     115                 : 
     116                 : /*
     117                 :  *  MAC address output function.  Fixed format.
     118                 :  */
     119                 : 
     120                 : Datum
     121 GIC        1604 : macaddr_out(PG_FUNCTION_ARGS)
     122 ECB             : {
     123 GIC        1604 :     macaddr    *addr = PG_GETARG_MACADDR_P(0);
     124 ECB             :     char       *result;
     125                 : 
     126 GIC        1604 :     result = (char *) palloc(32);
     127 ECB             : 
     128 GIC        1604 :     snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
     129 CBC        1604 :              addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
     130 ECB             : 
     131 GIC        1604 :     PG_RETURN_CSTRING(result);
     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
     140 UIC           0 : macaddr_recv(PG_FUNCTION_ARGS)
     141 EUB             : {
     142 UIC           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     143 EUB             :     macaddr    *addr;
     144                 : 
     145 UIC           0 :     addr = (macaddr *) palloc(sizeof(macaddr));
     146 EUB             : 
     147 UIC           0 :     addr->a = pq_getmsgbyte(buf);
     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);
     153 EUB             : 
     154 UIC           0 :     PG_RETURN_MACADDR_P(addr);
     155 EUB             : }
     156                 : 
     157                 : /*
     158                 :  *      macaddr_send            - converts macaddr to binary format
     159                 :  */
     160                 : Datum
     161 UIC           0 : macaddr_send(PG_FUNCTION_ARGS)
     162 EUB             : {
     163 UIC           0 :     macaddr    *addr = PG_GETARG_MACADDR_P(0);
     164 EUB             :     StringInfoData buf;
     165                 : 
     166 UIC           0 :     pq_begintypsend(&buf);
     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));
     174 EUB             : }
     175                 : 
     176                 : 
     177                 : /*
     178                 :  *  Comparison function for sorting:
     179                 :  */
     180                 : 
     181                 : static int
     182 GIC      102142 : macaddr_cmp_internal(macaddr *a1, macaddr *a2)
     183 ECB             : {
     184 GIC      102142 :     if (hibits(a1) < hibits(a2))
     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;
     192 ECB             :     else
     193 GIC        6341 :         return 0;
     194 ECB             : }
     195                 : 
     196                 : Datum
     197 GIC        6639 : macaddr_cmp(PG_FUNCTION_ARGS)
     198 ECB             : {
     199 GIC        6639 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     200 CBC        6639 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     201 ECB             : 
     202 GIC        6639 :     PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
     203 ECB             : }
     204                 : 
     205                 : /*
     206                 :  *  Boolean comparisons.
     207                 :  */
     208                 : 
     209                 : Datum
     210 GIC       70568 : macaddr_lt(PG_FUNCTION_ARGS)
     211 ECB             : {
     212 GIC       70568 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     213 CBC       70568 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     214 ECB             : 
     215 GIC       70568 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
     216 ECB             : }
     217                 : 
     218                 : Datum
     219 GIC        3118 : macaddr_le(PG_FUNCTION_ARGS)
     220 ECB             : {
     221 GIC        3118 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     222 CBC        3118 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     223 ECB             : 
     224 GIC        3118 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
     225 ECB             : }
     226                 : 
     227                 : Datum
     228 GIC       14669 : macaddr_eq(PG_FUNCTION_ARGS)
     229 ECB             : {
     230 GIC       14669 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     231 CBC       14669 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     232 ECB             : 
     233 GIC       14669 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
     234 ECB             : }
     235                 : 
     236                 : Datum
     237 GIC        2458 : macaddr_ge(PG_FUNCTION_ARGS)
     238 ECB             : {
     239 GIC        2458 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     240 CBC        2458 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     241 ECB             : 
     242 GIC        2458 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
     243 ECB             : }
     244                 : 
     245                 : Datum
     246 GIC        4516 : macaddr_gt(PG_FUNCTION_ARGS)
     247 ECB             : {
     248 GIC        4516 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     249 CBC        4516 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     250 ECB             : 
     251 GIC        4516 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
     252 ECB             : }
     253                 : 
     254                 : Datum
     255 GIC          12 : macaddr_ne(PG_FUNCTION_ARGS)
     256 ECB             : {
     257 GIC          12 :     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     258 CBC          12 :     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     259 ECB             : 
     260 GIC          12 :     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
     261 ECB             : }
     262                 : 
     263                 : /*
     264                 :  * Support function for hash indexes on macaddr.
     265                 :  */
     266                 : Datum
     267 GIC        1167 : hashmacaddr(PG_FUNCTION_ARGS)
     268 ECB             : {
     269 GIC        1167 :     macaddr    *key = PG_GETARG_MACADDR_P(0);
     270 ECB             : 
     271 GIC        1167 :     return hash_any((unsigned char *) key, sizeof(macaddr));
     272 ECB             : }
     273                 : 
     274                 : Datum
     275 GIC          30 : hashmacaddrextended(PG_FUNCTION_ARGS)
     276 ECB             : {
     277 GIC          30 :     macaddr    *key = PG_GETARG_MACADDR_P(0);
     278 ECB             : 
     279 GIC          30 :     return hash_any_extended((unsigned char *) key, sizeof(macaddr),
     280 CBC          30 :                              PG_GETARG_INT64(1));
     281 ECB             : }
     282                 : 
     283                 : /*
     284                 :  * Arithmetic functions: bitwise NOT, AND, OR.
     285                 :  */
     286                 : Datum
     287 GIC          36 : macaddr_not(PG_FUNCTION_ARGS)
     288 ECB             : {
     289 GIC          36 :     macaddr    *addr = PG_GETARG_MACADDR_P(0);
     290 ECB             :     macaddr    *result;
     291                 : 
     292 GIC          36 :     result = (macaddr *) palloc(sizeof(macaddr));
     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);
     300 ECB             : }
     301                 : 
     302                 : Datum
     303 GIC          36 : macaddr_and(PG_FUNCTION_ARGS)
     304 ECB             : {
     305 GIC          36 :     macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
     306 CBC          36 :     macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
     307 ECB             :     macaddr    *result;
     308                 : 
     309 GIC          36 :     result = (macaddr *) palloc(sizeof(macaddr));
     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);
     317 ECB             : }
     318                 : 
     319                 : Datum
     320 GIC          36 : macaddr_or(PG_FUNCTION_ARGS)
     321 ECB             : {
     322 GIC          36 :     macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
     323 CBC          36 :     macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
     324 ECB             :     macaddr    *result;
     325                 : 
     326 GIC          36 :     result = (macaddr *) palloc(sizeof(macaddr));
     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);
     334 ECB             : }
     335                 : 
     336                 : /*
     337                 :  *  Truncation function to allow comparing mac manufacturers.
     338                 :  *  From suggestion by Alex Pilosov <alex@pilosoft.com>
     339                 :  */
     340                 : Datum
     341 GIC          36 : macaddr_trunc(PG_FUNCTION_ARGS)
     342 ECB             : {
     343 GIC          36 :     macaddr    *addr = PG_GETARG_MACADDR_P(0);
     344 ECB             :     macaddr    *result;
     345                 : 
     346 GIC          36 :     result = (macaddr *) palloc(sizeof(macaddr));
     347 ECB             : 
     348 GIC          36 :     result->a = addr->a;
     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;
     354 ECB             : 
     355 GIC          36 :     PG_RETURN_MACADDR_P(result);
     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
     363 GIC          10 : macaddr_sortsupport(PG_FUNCTION_ARGS)
     364 ECB             : {
     365 GIC          10 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     366 ECB             : 
     367 GIC          10 :     ssup->comparator = macaddr_fast_cmp;
     368 CBC          10 :     ssup->ssup_extra = NULL;
     369 ECB             : 
     370 GIC          10 :     if (ssup->abbreviate)
     371 ECB             :     {
     372                 :         macaddr_sortsupport_state *uss;
     373                 :         MemoryContext oldcontext;
     374                 : 
     375 GIC          10 :         oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
     376 ECB             : 
     377 GIC          10 :         uss = palloc(sizeof(macaddr_sortsupport_state));
     378 CBC          10 :         uss->input_count = 0;
     379              10 :         uss->estimating = true;
     380              10 :         initHyperLogLog(&uss->abbr_card, 10);
     381 ECB             : 
     382 GIC          10 :         ssup->ssup_extra = uss;
     383 ECB             : 
     384 GIC          10 :         ssup->comparator = ssup_datum_unsigned_cmp;
     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;
     388 ECB             : 
     389 GIC          10 :         MemoryContextSwitchTo(oldcontext);
     390 ECB             :     }
     391                 : 
     392 GIC          10 :     PG_RETURN_VOID();
     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
     400 GIC         162 : macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup)
     401 ECB             : {
     402 GIC         162 :     macaddr    *arg1 = DatumGetMacaddrP(x);
     403 CBC         162 :     macaddr    *arg2 = DatumGetMacaddrP(y);
     404 ECB             : 
     405 GIC         162 :     return macaddr_cmp_internal(arg1, arg2);
     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
     415 GIC           6 : macaddr_abbrev_abort(int memtupcount, SortSupport ssup)
     416 ECB             : {
     417 GIC           6 :     macaddr_sortsupport_state *uss = ssup->ssup_extra;
     418 ECB             :     double      abbr_card;
     419                 : 
     420 GIC           6 :     if (memtupcount < 10000 || uss->input_count < 10000 || !uss->estimating)
     421 CBC           6 :         return false;
     422 ECB             : 
     423 UIC           0 :     abbr_card = estimateHyperLogLog(&uss->abbr_card);
     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                 :      */
     431 UIC           0 :     if (abbr_card > 100000.0)
     432 EUB             :     {
     433                 : #ifdef TRACE_SORT
     434 UIC           0 :         if (trace_sort)
     435 UBC           0 :             elog(LOG,
     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
     440 UIC           0 :         uss->estimating = false;
     441 UBC           0 :         return false;
     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                 :      */
     450 UIC           0 :     if (abbr_card < uss->input_count / 2000.0 + 0.5)
     451 EUB             :     {
     452                 : #ifdef TRACE_SORT
     453 UIC           0 :         if (trace_sort)
     454 UBC           0 :             elog(LOG,
     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
     460 UIC           0 :         return true;
     461 EUB             :     }
     462                 : 
     463                 : #ifdef TRACE_SORT
     464 UIC           0 :     if (trace_sort)
     465 UBC           0 :         elog(LOG,
     466 EUB             :              "macaddr_abbrev: cardinality %f after " INT64_FORMAT
     467                 :              " values (%d rows)", abbr_card, uss->input_count, memtupcount);
     468                 : #endif
     469                 : 
     470 UIC           0 :     return false;
     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
     483 GIC          84 : macaddr_abbrev_convert(Datum original, SortSupport ssup)
     484 ECB             : {
     485 GIC          84 :     macaddr_sortsupport_state *uss = ssup->ssup_extra;
     486 CBC          84 :     macaddr    *authoritative = DatumGetMacaddrP(original);
     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
     495 GIC          84 :     memset(&res, 0, SIZEOF_DATUM);
     496 CBC          84 :     memcpy(&res, authoritative, sizeof(macaddr));
     497 ECB             : #else                           /* SIZEOF_DATUM != 8 */
     498                 :     memcpy(&res, authoritative, SIZEOF_DATUM);
     499                 : #endif
     500 GIC          84 :     uss->input_count += 1;
     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                 :      */
     508 GIC          84 :     if (uss->estimating)
     509 ECB             :     {
     510                 :         uint32      tmp;
     511                 : 
     512                 : #if SIZEOF_DATUM == 8
     513 GIC          84 :         tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
     514 ECB             : #else                           /* SIZEOF_DATUM != 8 */
     515                 :         tmp = (uint32) res;
     516                 : #endif
     517                 : 
     518 GIC          84 :         addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
     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                 :      */
     529 GIC          84 :     res = DatumBigEndianToNative(res);
     530 ECB             : 
     531 GIC          84 :     return res;
     532 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a