LCOV - code coverage report
Current view: top level - src/backend/utils/adt - mac.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 81.6 % 239 195
Test Date: 2026-01-26 10:56:24 Functions: 86.4 % 22 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 45.1 % 82 37

             Branch data     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-2026, 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/fmgrprotos.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                 :         410 : macaddr_in(PG_FUNCTION_ARGS)
      56                 :             : {
      57                 :         410 :         char       *str = PG_GETARG_CSTRING(0);
      58                 :         410 :         Node       *escontext = fcinfo->context;
      59                 :         410 :         macaddr    *result;
      60                 :         410 :         int                     a,
      61                 :             :                                 b,
      62                 :             :                                 c,
      63                 :             :                                 d,
      64                 :             :                                 e,
      65                 :             :                                 f;
      66                 :         410 :         char            junk[2];
      67                 :         410 :         int                     count;
      68                 :             : 
      69                 :             :         /* %1s matches iff there is trailing non-whitespace garbage */
      70                 :             : 
      71                 :         820 :         count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
      72                 :         410 :                                    &a, &b, &c, &d, &e, &f, junk);
      73         [ +  + ]:         410 :         if (count != 6)
      74                 :          24 :                 count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
      75                 :          12 :                                            &a, &b, &c, &d, &e, &f, junk);
      76         [ +  + ]:         410 :         if (count != 6)
      77                 :          22 :                 count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
      78                 :          11 :                                            &a, &b, &c, &d, &e, &f, junk);
      79         [ +  + ]:         410 :         if (count != 6)
      80                 :          20 :                 count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
      81                 :          10 :                                            &a, &b, &c, &d, &e, &f, junk);
      82         [ +  + ]:         410 :         if (count != 6)
      83                 :          18 :                 count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
      84                 :           9 :                                            &a, &b, &c, &d, &e, &f, junk);
      85         [ +  + ]:         410 :         if (count != 6)
      86                 :          16 :                 count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
      87                 :           8 :                                            &a, &b, &c, &d, &e, &f, junk);
      88         [ +  + ]:         410 :         if (count != 6)
      89                 :          14 :                 count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
      90                 :           7 :                                            &a, &b, &c, &d, &e, &f, junk);
      91         [ +  + ]:         410 :         if (count != 6)
      92         [ -  + ]:           4 :                 ereturn(escontext, (Datum) 0,
      93                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      94                 :             :                                  errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
      95                 :             :                                                 str)));
      96                 :             : 
      97   [ +  -  +  -  :         406 :         if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
             +  -  +  - ]
      98   [ +  -  +  -  :         406 :                 (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
             +  -  +  - ]
      99   [ +  -  +  -  :         406 :                 (e < 0) || (e > 255) || (f < 0) || (f > 255))
             +  -  -  + ]
     100         [ #  # ]:           0 :                 ereturn(escontext, (Datum) 0,
     101                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     102                 :             :                                  errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
     103                 :             : 
     104                 :         406 :         result = palloc_object(macaddr);
     105                 :             : 
     106                 :         406 :         result->a = a;
     107                 :         406 :         result->b = b;
     108                 :         406 :         result->c = c;
     109                 :         406 :         result->d = d;
     110                 :         406 :         result->e = e;
     111                 :         406 :         result->f = f;
     112                 :             : 
     113                 :         406 :         PG_RETURN_MACADDR_P(result);
     114                 :         410 : }
     115                 :             : 
     116                 :             : /*
     117                 :             :  *      MAC address output function.  Fixed format.
     118                 :             :  */
     119                 :             : 
     120                 :             : Datum
     121                 :         105 : macaddr_out(PG_FUNCTION_ARGS)
     122                 :             : {
     123                 :         105 :         macaddr    *addr = PG_GETARG_MACADDR_P(0);
     124                 :         105 :         char       *result;
     125                 :             : 
     126                 :         105 :         result = (char *) palloc(32);
     127                 :             : 
     128                 :         210 :         snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
     129                 :         105 :                          addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
     130                 :             : 
     131                 :         210 :         PG_RETURN_CSTRING(result);
     132                 :         105 : }
     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                 :           0 : macaddr_recv(PG_FUNCTION_ARGS)
     141                 :             : {
     142                 :           0 :         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
     143                 :           0 :         macaddr    *addr;
     144                 :             : 
     145                 :           0 :         addr = palloc_object(macaddr);
     146                 :             : 
     147                 :           0 :         addr->a = pq_getmsgbyte(buf);
     148                 :           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                 :             : 
     154                 :           0 :         PG_RETURN_MACADDR_P(addr);
     155                 :           0 : }
     156                 :             : 
     157                 :             : /*
     158                 :             :  *              macaddr_send                    - converts macaddr to binary format
     159                 :             :  */
     160                 :             : Datum
     161                 :           0 : macaddr_send(PG_FUNCTION_ARGS)
     162                 :             : {
     163                 :           0 :         macaddr    *addr = PG_GETARG_MACADDR_P(0);
     164                 :           0 :         StringInfoData buf;
     165                 :             : 
     166                 :           0 :         pq_begintypsend(&buf);
     167                 :           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                 :           0 : }
     175                 :             : 
     176                 :             : 
     177                 :             : /*
     178                 :             :  *      Comparison function for sorting:
     179                 :             :  */
     180                 :             : 
     181                 :             : static int
     182                 :       29071 : macaddr_cmp_internal(macaddr *a1, macaddr *a2)
     183                 :             : {
     184         [ +  + ]:       29071 :         if (hibits(a1) < hibits(a2))
     185                 :       13903 :                 return -1;
     186         [ +  + ]:       15168 :         else if (hibits(a1) > hibits(a2))
     187                 :       13952 :                 return 1;
     188         [ +  + ]:        1216 :         else if (lobits(a1) < lobits(a2))
     189                 :           8 :                 return -1;
     190         [ -  + ]:        1208 :         else if (lobits(a1) > lobits(a2))
     191                 :           0 :                 return 1;
     192                 :             :         else
     193                 :        1208 :                 return 0;
     194                 :       29071 : }
     195                 :             : 
     196                 :             : Datum
     197                 :           0 : macaddr_cmp(PG_FUNCTION_ARGS)
     198                 :             : {
     199                 :           0 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     200                 :           0 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     201                 :             : 
     202                 :           0 :         PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
     203                 :           0 : }
     204                 :             : 
     205                 :             : /*
     206                 :             :  *      Boolean comparisons.
     207                 :             :  */
     208                 :             : 
     209                 :             : Datum
     210                 :       22663 : macaddr_lt(PG_FUNCTION_ARGS)
     211                 :             : {
     212                 :       22663 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     213                 :       22663 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     214                 :             : 
     215                 :       45326 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
     216                 :       22663 : }
     217                 :             : 
     218                 :             : Datum
     219                 :         635 : macaddr_le(PG_FUNCTION_ARGS)
     220                 :             : {
     221                 :         635 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     222                 :         635 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     223                 :             : 
     224                 :        1270 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
     225                 :         635 : }
     226                 :             : 
     227                 :             : Datum
     228                 :        4405 : macaddr_eq(PG_FUNCTION_ARGS)
     229                 :             : {
     230                 :        4405 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     231                 :        4405 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     232                 :             : 
     233                 :        8810 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
     234                 :        4405 : }
     235                 :             : 
     236                 :             : Datum
     237                 :         565 : macaddr_ge(PG_FUNCTION_ARGS)
     238                 :             : {
     239                 :         565 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     240                 :         565 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     241                 :             : 
     242                 :        1130 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
     243                 :         565 : }
     244                 :             : 
     245                 :             : Datum
     246                 :         745 : macaddr_gt(PG_FUNCTION_ARGS)
     247                 :             : {
     248                 :         745 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     249                 :         745 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     250                 :             : 
     251                 :        1490 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
     252                 :         745 : }
     253                 :             : 
     254                 :             : Datum
     255                 :           4 : macaddr_ne(PG_FUNCTION_ARGS)
     256                 :             : {
     257                 :           4 :         macaddr    *a1 = PG_GETARG_MACADDR_P(0);
     258                 :           4 :         macaddr    *a2 = PG_GETARG_MACADDR_P(1);
     259                 :             : 
     260                 :           8 :         PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
     261                 :           4 : }
     262                 :             : 
     263                 :             : /*
     264                 :             :  * Support function for hash indexes on macaddr.
     265                 :             :  */
     266                 :             : Datum
     267                 :         389 : hashmacaddr(PG_FUNCTION_ARGS)
     268                 :             : {
     269                 :         389 :         macaddr    *key = PG_GETARG_MACADDR_P(0);
     270                 :             : 
     271                 :         778 :         return hash_any((unsigned char *) key, sizeof(macaddr));
     272                 :         389 : }
     273                 :             : 
     274                 :             : Datum
     275                 :          10 : hashmacaddrextended(PG_FUNCTION_ARGS)
     276                 :             : {
     277                 :          10 :         macaddr    *key = PG_GETARG_MACADDR_P(0);
     278                 :             : 
     279                 :          30 :         return hash_any_extended((unsigned char *) key, sizeof(macaddr),
     280                 :          10 :                                                          PG_GETARG_INT64(1));
     281                 :          10 : }
     282                 :             : 
     283                 :             : /*
     284                 :             :  * Arithmetic functions: bitwise NOT, AND, OR.
     285                 :             :  */
     286                 :             : Datum
     287                 :          12 : macaddr_not(PG_FUNCTION_ARGS)
     288                 :             : {
     289                 :          12 :         macaddr    *addr = PG_GETARG_MACADDR_P(0);
     290                 :          12 :         macaddr    *result;
     291                 :             : 
     292                 :          12 :         result = palloc_object(macaddr);
     293                 :          12 :         result->a = ~addr->a;
     294                 :          12 :         result->b = ~addr->b;
     295                 :          12 :         result->c = ~addr->c;
     296                 :          12 :         result->d = ~addr->d;
     297                 :          12 :         result->e = ~addr->e;
     298                 :          12 :         result->f = ~addr->f;
     299                 :          24 :         PG_RETURN_MACADDR_P(result);
     300                 :          12 : }
     301                 :             : 
     302                 :             : Datum
     303                 :          12 : macaddr_and(PG_FUNCTION_ARGS)
     304                 :             : {
     305                 :          12 :         macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
     306                 :          12 :         macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
     307                 :          12 :         macaddr    *result;
     308                 :             : 
     309                 :          12 :         result = palloc_object(macaddr);
     310                 :          12 :         result->a = addr1->a & addr2->a;
     311                 :          12 :         result->b = addr1->b & addr2->b;
     312                 :          12 :         result->c = addr1->c & addr2->c;
     313                 :          12 :         result->d = addr1->d & addr2->d;
     314                 :          12 :         result->e = addr1->e & addr2->e;
     315                 :          12 :         result->f = addr1->f & addr2->f;
     316                 :          24 :         PG_RETURN_MACADDR_P(result);
     317                 :          12 : }
     318                 :             : 
     319                 :             : Datum
     320                 :          12 : macaddr_or(PG_FUNCTION_ARGS)
     321                 :             : {
     322                 :          12 :         macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
     323                 :          12 :         macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
     324                 :          12 :         macaddr    *result;
     325                 :             : 
     326                 :          12 :         result = palloc_object(macaddr);
     327                 :          12 :         result->a = addr1->a | addr2->a;
     328                 :          12 :         result->b = addr1->b | addr2->b;
     329                 :          12 :         result->c = addr1->c | addr2->c;
     330                 :          12 :         result->d = addr1->d | addr2->d;
     331                 :          12 :         result->e = addr1->e | addr2->e;
     332                 :          12 :         result->f = addr1->f | addr2->f;
     333                 :          24 :         PG_RETURN_MACADDR_P(result);
     334                 :          12 : }
     335                 :             : 
     336                 :             : /*
     337                 :             :  *      Truncation function to allow comparing mac manufacturers.
     338                 :             :  *      From suggestion by Alex Pilosov <alex@pilosoft.com>
     339                 :             :  */
     340                 :             : Datum
     341                 :          12 : macaddr_trunc(PG_FUNCTION_ARGS)
     342                 :             : {
     343                 :          12 :         macaddr    *addr = PG_GETARG_MACADDR_P(0);
     344                 :          12 :         macaddr    *result;
     345                 :             : 
     346                 :          12 :         result = palloc_object(macaddr);
     347                 :             : 
     348                 :          12 :         result->a = addr->a;
     349                 :          12 :         result->b = addr->b;
     350                 :          12 :         result->c = addr->c;
     351                 :          12 :         result->d = 0;
     352                 :          12 :         result->e = 0;
     353                 :          12 :         result->f = 0;
     354                 :             : 
     355                 :          24 :         PG_RETURN_MACADDR_P(result);
     356                 :          12 : }
     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                 :           2 : macaddr_sortsupport(PG_FUNCTION_ARGS)
     364                 :             : {
     365                 :           2 :         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     366                 :             : 
     367                 :           2 :         ssup->comparator = macaddr_fast_cmp;
     368                 :           2 :         ssup->ssup_extra = NULL;
     369                 :             : 
     370         [ -  + ]:           2 :         if (ssup->abbreviate)
     371                 :             :         {
     372                 :           2 :                 macaddr_sortsupport_state *uss;
     373                 :           2 :                 MemoryContext oldcontext;
     374                 :             : 
     375                 :           2 :                 oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
     376                 :             : 
     377                 :           2 :                 uss = palloc_object(macaddr_sortsupport_state);
     378                 :           2 :                 uss->input_count = 0;
     379                 :           2 :                 uss->estimating = true;
     380                 :           2 :                 initHyperLogLog(&uss->abbr_card, 10);
     381                 :             : 
     382                 :           2 :                 ssup->ssup_extra = uss;
     383                 :             : 
     384                 :           2 :                 ssup->comparator = ssup_datum_unsigned_cmp;
     385                 :           2 :                 ssup->abbrev_converter = macaddr_abbrev_convert;
     386                 :           2 :                 ssup->abbrev_abort = macaddr_abbrev_abort;
     387                 :           2 :                 ssup->abbrev_full_comparator = macaddr_fast_cmp;
     388                 :             : 
     389                 :           2 :                 MemoryContextSwitchTo(oldcontext);
     390                 :           2 :         }
     391                 :             : 
     392                 :           2 :         PG_RETURN_VOID();
     393                 :           2 : }
     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                 :          54 : macaddr_fast_cmp(Datum x, Datum y, SortSupport ssup)
     401                 :             : {
     402                 :          54 :         macaddr    *arg1 = DatumGetMacaddrP(x);
     403                 :          54 :         macaddr    *arg2 = DatumGetMacaddrP(y);
     404                 :             : 
     405                 :         108 :         return macaddr_cmp_internal(arg1, arg2);
     406                 :          54 : }
     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                 :           2 : macaddr_abbrev_abort(int memtupcount, SortSupport ssup)
     416                 :             : {
     417                 :           2 :         macaddr_sortsupport_state *uss = ssup->ssup_extra;
     418                 :           2 :         double          abbr_card;
     419                 :             : 
     420   [ -  +  #  #  :           2 :         if (memtupcount < 10000 || uss->input_count < 10000 || !uss->estimating)
                   #  # ]
     421                 :           2 :                 return false;
     422                 :             : 
     423                 :           0 :         abbr_card = estimateHyperLogLog(&uss->abbr_card);
     424                 :             : 
     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         [ #  # ]:           0 :         if (abbr_card > 100000.0)
     432                 :             :         {
     433         [ #  # ]:           0 :                 if (trace_sort)
     434   [ #  #  #  # ]:           0 :                         elog(LOG,
     435                 :             :                                  "macaddr_abbrev: estimation ends at cardinality %f"
     436                 :             :                                  " after " INT64_FORMAT " values (%d rows)",
     437                 :             :                                  abbr_card, uss->input_count, memtupcount);
     438                 :           0 :                 uss->estimating = false;
     439                 :           0 :                 return false;
     440                 :             :         }
     441                 :             : 
     442                 :             :         /*
     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
     446                 :             :          * (non-null) rows.
     447                 :             :          */
     448         [ #  # ]:           0 :         if (abbr_card < uss->input_count / 2000.0 + 0.5)
     449                 :             :         {
     450         [ #  # ]:           0 :                 if (trace_sort)
     451   [ #  #  #  # ]:           0 :                         elog(LOG,
     452                 :             :                                  "macaddr_abbrev: aborting abbreviation at cardinality %f"
     453                 :             :                                  " below threshold %f after " INT64_FORMAT " values (%d rows)",
     454                 :             :                                  abbr_card, uss->input_count / 2000.0 + 0.5, uss->input_count,
     455                 :             :                                  memtupcount);
     456                 :           0 :                 return true;
     457                 :             :         }
     458                 :             : 
     459         [ #  # ]:           0 :         if (trace_sort)
     460   [ #  #  #  # ]:           0 :                 elog(LOG,
     461                 :             :                          "macaddr_abbrev: cardinality %f after " INT64_FORMAT
     462                 :             :                          " values (%d rows)", abbr_card, uss->input_count, memtupcount);
     463                 :             : 
     464                 :           0 :         return false;
     465                 :           2 : }
     466                 :             : 
     467                 :             : /*
     468                 :             :  * SortSupport conversion routine. Converts original macaddr representation
     469                 :             :  * to abbreviated key representation.
     470                 :             :  *
     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.
     475                 :             :  */
     476                 :             : static Datum
     477                 :          24 : macaddr_abbrev_convert(Datum original, SortSupport ssup)
     478                 :             : {
     479                 :          24 :         macaddr_sortsupport_state *uss = ssup->ssup_extra;
     480                 :          24 :         macaddr    *authoritative = DatumGetMacaddrP(original);
     481                 :          24 :         Datum           res;
     482                 :             : 
     483                 :             :         /*
     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
     486                 :             :          * significant bits.
     487                 :             :          */
     488                 :             :         StaticAssertDecl(sizeof(res) >= sizeof(macaddr),
     489                 :             :                                          "Datum is too small for macaddr");
     490                 :          24 :         memset(&res, 0, sizeof(res));
     491                 :          24 :         memcpy(&res, authoritative, sizeof(macaddr));
     492                 :          24 :         uss->input_count += 1;
     493                 :             : 
     494                 :             :         /*
     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.
     498                 :             :          */
     499         [ -  + ]:          24 :         if (uss->estimating)
     500                 :             :         {
     501                 :          24 :                 uint32          tmp;
     502                 :             : 
     503                 :          24 :                 tmp = DatumGetUInt32(res) ^ (uint32) (DatumGetUInt64(res) >> 32);
     504                 :             : 
     505                 :          24 :                 addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
     506                 :          24 :         }
     507                 :             : 
     508                 :             :         /*
     509                 :             :          * Byteswap on little-endian machines.
     510                 :             :          *
     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.
     515                 :             :          */
     516                 :          24 :         res = DatumBigEndianToNative(res);
     517                 :             : 
     518                 :          48 :         return res;
     519                 :          24 : }
        

Generated by: LCOV version 2.3.2-1