LCOV - code coverage report
Current view: top level - src/backend/utils/adt - network_gist.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 23.9 % 309 74
Test Date: 2026-01-26 10:56:24 Functions: 10.0 % 10 1
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.5 % 176 66

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * network_gist.c
       4                 :             :  *        GiST support for network types.
       5                 :             :  *
       6                 :             :  * The key thing to understand about this code is the definition of the
       7                 :             :  * "union" of a set of INET/CIDR values.  It works like this:
       8                 :             :  * 1. If the values are not all of the same IP address family, the "union"
       9                 :             :  * is a dummy value with family number zero, minbits zero, commonbits zero,
      10                 :             :  * address all zeroes.  Otherwise:
      11                 :             :  * 2. The union has the common IP address family number.
      12                 :             :  * 3. The union's minbits value is the smallest netmask length ("ip_bits")
      13                 :             :  * of all the input values.
      14                 :             :  * 4. Let C be the number of leading address bits that are in common among
      15                 :             :  * all the input values (C ranges from 0 to ip_maxbits for the family).
      16                 :             :  * 5. The union's commonbits value is C.
      17                 :             :  * 6. The union's address value is the same as the common prefix for its
      18                 :             :  * first C bits, and is zeroes to the right of that.  The physical width
      19                 :             :  * of the address value is ip_maxbits for the address family.
      20                 :             :  *
      21                 :             :  * In a leaf index entry (representing a single key), commonbits is equal to
      22                 :             :  * ip_maxbits for the address family, minbits is the same as the represented
      23                 :             :  * value's ip_bits, and the address is equal to the represented address.
      24                 :             :  * Although it may appear that we're wasting a byte by storing the union
      25                 :             :  * format and not just the represented INET/CIDR value in leaf keys, the
      26                 :             :  * extra byte is actually "free" because of alignment considerations.
      27                 :             :  *
      28                 :             :  * Note that this design tracks minbits and commonbits independently; in any
      29                 :             :  * given union value, either might be smaller than the other.  This does not
      30                 :             :  * help us much when descending the tree, because of the way inet comparison
      31                 :             :  * is defined: at non-leaf nodes we can't compare more than minbits bits
      32                 :             :  * even if we know them.  However, it greatly improves the quality of split
      33                 :             :  * decisions.  Preliminary testing suggests that searches are as much as
      34                 :             :  * twice as fast as for a simpler design in which a single field doubles as
      35                 :             :  * the common prefix length and the minimum ip_bits value.
      36                 :             :  *
      37                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      38                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      39                 :             :  *
      40                 :             :  *
      41                 :             :  * IDENTIFICATION
      42                 :             :  *        src/backend/utils/adt/network_gist.c
      43                 :             :  *
      44                 :             :  *-------------------------------------------------------------------------
      45                 :             :  */
      46                 :             : #include "postgres.h"
      47                 :             : 
      48                 :             : #include <sys/socket.h>
      49                 :             : 
      50                 :             : #include "access/gist.h"
      51                 :             : #include "access/stratnum.h"
      52                 :             : #include "utils/fmgrprotos.h"
      53                 :             : #include "utils/inet.h"
      54                 :             : #include "varatt.h"
      55                 :             : 
      56                 :             : /*
      57                 :             :  * Operator strategy numbers used in the GiST inet_ops opclass
      58                 :             :  */
      59                 :             : #define INETSTRAT_OVERLAPS              RTOverlapStrategyNumber
      60                 :             : #define INETSTRAT_EQ                    RTEqualStrategyNumber
      61                 :             : #define INETSTRAT_NE                    RTNotEqualStrategyNumber
      62                 :             : #define INETSTRAT_LT                    RTLessStrategyNumber
      63                 :             : #define INETSTRAT_LE                    RTLessEqualStrategyNumber
      64                 :             : #define INETSTRAT_GT                    RTGreaterStrategyNumber
      65                 :             : #define INETSTRAT_GE                    RTGreaterEqualStrategyNumber
      66                 :             : #define INETSTRAT_SUB                   RTSubStrategyNumber
      67                 :             : #define INETSTRAT_SUBEQ                 RTSubEqualStrategyNumber
      68                 :             : #define INETSTRAT_SUP                   RTSuperStrategyNumber
      69                 :             : #define INETSTRAT_SUPEQ                 RTSuperEqualStrategyNumber
      70                 :             : 
      71                 :             : 
      72                 :             : /*
      73                 :             :  * Representation of a GiST INET/CIDR index key.  This is not identical to
      74                 :             :  * INET/CIDR because we need to keep track of the length of the common address
      75                 :             :  * prefix as well as the minimum netmask length.  However, as long as it
      76                 :             :  * follows varlena header rules, the core GiST code won't know the difference.
      77                 :             :  * For simplicity we always use 1-byte-header varlena format.
      78                 :             :  */
      79                 :             : typedef struct GistInetKey
      80                 :             : {
      81                 :             :         uint8           va_header;              /* varlena header --- don't touch directly */
      82                 :             :         unsigned char family;           /* PGSQL_AF_INET, PGSQL_AF_INET6, or zero */
      83                 :             :         unsigned char minbits;          /* minimum number of bits in netmask */
      84                 :             :         unsigned char commonbits;       /* number of common prefix bits in addresses */
      85                 :             :         unsigned char ipaddr[16];       /* up to 128 bits of common address */
      86                 :             : } GistInetKey;
      87                 :             : 
      88                 :             : #define DatumGetInetKeyP(X) ((GistInetKey *) DatumGetPointer(X))
      89                 :             : #define InetKeyPGetDatum(X) PointerGetDatum(X)
      90                 :             : 
      91                 :             : /*
      92                 :             :  * Access macros; not really exciting, but we use these for notational
      93                 :             :  * consistency with access to INET/CIDR values.  Note that family-zero values
      94                 :             :  * are stored with 4 bytes of address, not 16.
      95                 :             :  */
      96                 :             : #define gk_ip_family(gkptr)             ((gkptr)->family)
      97                 :             : #define gk_ip_minbits(gkptr)    ((gkptr)->minbits)
      98                 :             : #define gk_ip_commonbits(gkptr) ((gkptr)->commonbits)
      99                 :             : #define gk_ip_addr(gkptr)               ((gkptr)->ipaddr)
     100                 :             : #define ip_family_maxbits(fam)  ((fam) == PGSQL_AF_INET6 ? 128 : 32)
     101                 :             : 
     102                 :             : /* These require that the family field has been set: */
     103                 :             : #define gk_ip_addrsize(gkptr) \
     104                 :             :         (gk_ip_family(gkptr) == PGSQL_AF_INET6 ? 16 : 4)
     105                 :             : #define gk_ip_maxbits(gkptr) \
     106                 :             :         ip_family_maxbits(gk_ip_family(gkptr))
     107                 :             : #define SET_GK_VARSIZE(dst) \
     108                 :             :         SET_VARSIZE_SHORT(dst, offsetof(GistInetKey, ipaddr) + gk_ip_addrsize(dst))
     109                 :             : 
     110                 :             : 
     111                 :             : /*
     112                 :             :  * The GiST query consistency check
     113                 :             :  */
     114                 :             : Datum
     115                 :         204 : inet_gist_consistent(PG_FUNCTION_ARGS)
     116                 :             : {
     117                 :         204 :         GISTENTRY  *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
     118                 :         204 :         inet       *query = PG_GETARG_INET_PP(1);
     119                 :         204 :         StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     120                 :             : #ifdef NOT_USED
     121                 :             :         Oid                     subtype = PG_GETARG_OID(3);
     122                 :             : #endif
     123                 :         204 :         bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     124                 :         204 :         GistInetKey *key = DatumGetInetKeyP(ent->key);
     125                 :         204 :         int                     minbits,
     126                 :             :                                 order;
     127                 :             : 
     128                 :             :         /* All operators served by this function are exact. */
     129                 :         204 :         *recheck = false;
     130                 :             : 
     131                 :             :         /*
     132                 :             :          * Check 0: different families
     133                 :             :          *
     134                 :             :          * If key represents multiple address families, its children could match
     135                 :             :          * anything.  This can only happen on an inner index page.
     136                 :             :          */
     137         [ +  - ]:         204 :         if (gk_ip_family(key) == 0)
     138                 :             :         {
     139         [ #  # ]:           0 :                 Assert(!GIST_LEAF(ent));
     140                 :           0 :                 PG_RETURN_BOOL(true);
     141                 :             :         }
     142                 :             : 
     143                 :             :         /*
     144                 :             :          * Check 1: different families
     145                 :             :          *
     146                 :             :          * Matching families do not help any of the strategies.
     147                 :             :          */
     148         [ +  + ]:         204 :         if (gk_ip_family(key) != ip_family(query))
     149                 :             :         {
     150   [ +  +  +  + ]:          36 :                 switch (strategy)
     151                 :             :                 {
     152                 :             :                         case INETSTRAT_LT:
     153                 :             :                         case INETSTRAT_LE:
     154         [ -  + ]:           6 :                                 if (gk_ip_family(key) < ip_family(query))
     155                 :           0 :                                         PG_RETURN_BOOL(true);
     156                 :           6 :                                 break;
     157                 :             : 
     158                 :             :                         case INETSTRAT_GE:
     159                 :             :                         case INETSTRAT_GT:
     160         [ +  - ]:           6 :                                 if (gk_ip_family(key) > ip_family(query))
     161                 :           6 :                                         PG_RETURN_BOOL(true);
     162                 :           0 :                                 break;
     163                 :             : 
     164                 :             :                         case INETSTRAT_NE:
     165                 :           3 :                                 PG_RETURN_BOOL(true);
     166                 :             :                 }
     167                 :             :                 /* For all other cases, we can be sure there is no match */
     168                 :          27 :                 PG_RETURN_BOOL(false);
     169                 :             :         }
     170                 :             : 
     171                 :             :         /*
     172                 :             :          * Check 2: network bit count
     173                 :             :          *
     174                 :             :          * Network bit count (ip_bits) helps to check leaves for sub network and
     175                 :             :          * sup network operators.  At non-leaf nodes, we know every child value
     176                 :             :          * has ip_bits >= gk_ip_minbits(key), so we can avoid descending in some
     177                 :             :          * cases too.
     178                 :             :          */
     179   [ +  +  +  +  :         168 :         switch (strategy)
                      + ]
     180                 :             :         {
     181                 :             :                 case INETSTRAT_SUB:
     182   [ +  -  +  + ]:          28 :                         if (GIST_LEAF(ent) && gk_ip_minbits(key) <= ip_bits(query))
     183                 :          20 :                                 PG_RETURN_BOOL(false);
     184                 :           8 :                         break;
     185                 :             : 
     186                 :             :                 case INETSTRAT_SUBEQ:
     187   [ +  -  +  + ]:          14 :                         if (GIST_LEAF(ent) && gk_ip_minbits(key) < ip_bits(query))
     188                 :           6 :                                 PG_RETURN_BOOL(false);
     189                 :           8 :                         break;
     190                 :             : 
     191                 :             :                 case INETSTRAT_SUPEQ:
     192                 :             :                 case INETSTRAT_EQ:
     193         [ +  + ]:          28 :                         if (gk_ip_minbits(key) > ip_bits(query))
     194                 :           8 :                                 PG_RETURN_BOOL(false);
     195                 :          20 :                         break;
     196                 :             : 
     197                 :             :                 case INETSTRAT_SUP:
     198         [ +  + ]:          14 :                         if (gk_ip_minbits(key) >= ip_bits(query))
     199                 :           8 :                                 PG_RETURN_BOOL(false);
     200                 :           6 :                         break;
     201                 :             :         }
     202                 :             : 
     203                 :             :         /*
     204                 :             :          * Check 3: common network bits
     205                 :             :          *
     206                 :             :          * Compare available common prefix bits to the query, but not beyond
     207                 :             :          * either the query's netmask or the minimum netmask among the represented
     208                 :             :          * values.  If these bits don't match the query, we have our answer (and
     209                 :             :          * may or may not need to descend, depending on the operator).  If they do
     210                 :             :          * match, and we are not at a leaf, we descend in all cases.
     211                 :             :          *
     212                 :             :          * Note this is the final check for operators that only consider the
     213                 :             :          * network part of the address.
     214                 :             :          */
     215         [ -  + ]:         126 :         minbits = Min(gk_ip_commonbits(key), gk_ip_minbits(key));
     216         [ +  + ]:         126 :         minbits = Min(minbits, ip_bits(query));
     217                 :             : 
     218                 :         126 :         order = bitncmp(gk_ip_addr(key), ip_addr(query), minbits);
     219                 :             : 
     220   [ +  +  +  -  :         126 :         switch (strategy)
                   +  + ]
     221                 :             :         {
     222                 :             :                 case INETSTRAT_SUB:
     223                 :             :                 case INETSTRAT_SUBEQ:
     224                 :             :                 case INETSTRAT_OVERLAPS:
     225                 :             :                 case INETSTRAT_SUPEQ:
     226                 :             :                 case INETSTRAT_SUP:
     227                 :          46 :                         PG_RETURN_BOOL(order == 0);
     228                 :             : 
     229                 :             :                 case INETSTRAT_LT:
     230                 :             :                 case INETSTRAT_LE:
     231         [ -  + ]:          28 :                         if (order > 0)
     232                 :           0 :                                 PG_RETURN_BOOL(false);
     233   [ +  +  -  + ]:          28 :                         if (order < 0 || !GIST_LEAF(ent))
     234                 :          16 :                                 PG_RETURN_BOOL(true);
     235                 :          12 :                         break;
     236                 :             : 
     237                 :             :                 case INETSTRAT_EQ:
     238         [ +  + ]:          10 :                         if (order != 0)
     239                 :           7 :                                 PG_RETURN_BOOL(false);
     240         [ +  - ]:           3 :                         if (!GIST_LEAF(ent))
     241                 :           0 :                                 PG_RETURN_BOOL(true);
     242                 :           3 :                         break;
     243                 :             : 
     244                 :             :                 case INETSTRAT_GE:
     245                 :             :                 case INETSTRAT_GT:
     246         [ +  + ]:          28 :                         if (order < 0)
     247                 :          16 :                                 PG_RETURN_BOOL(false);
     248   [ +  -  -  + ]:          12 :                         if (order > 0 || !GIST_LEAF(ent))
     249                 :           0 :                                 PG_RETURN_BOOL(true);
     250                 :          12 :                         break;
     251                 :             : 
     252                 :             :                 case INETSTRAT_NE:
     253   [ +  +  -  + ]:          14 :                         if (order != 0 || !GIST_LEAF(ent))
     254                 :           8 :                                 PG_RETURN_BOOL(true);
     255                 :           6 :                         break;
     256                 :             :         }
     257                 :             : 
     258                 :             :         /*
     259                 :             :          * Remaining checks are only for leaves and basic comparison strategies.
     260                 :             :          * See network_cmp_internal() in network.c for the implementation we need
     261                 :             :          * to match.  Note that in a leaf key, commonbits should equal the address
     262                 :             :          * length, so we compared the whole network parts above.
     263                 :             :          */
     264         [ +  - ]:          33 :         Assert(GIST_LEAF(ent));
     265                 :             : 
     266                 :             :         /*
     267                 :             :          * Check 4: network bit count
     268                 :             :          *
     269                 :             :          * Next step is to compare netmask widths.
     270                 :             :          */
     271   [ +  +  -  +  :          33 :         switch (strategy)
                      + ]
     272                 :             :         {
     273                 :             :                 case INETSTRAT_LT:
     274                 :             :                 case INETSTRAT_LE:
     275         [ -  + ]:          12 :                         if (gk_ip_minbits(key) < ip_bits(query))
     276                 :           0 :                                 PG_RETURN_BOOL(true);
     277         [ +  + ]:          12 :                         if (gk_ip_minbits(key) > ip_bits(query))
     278                 :           6 :                                 PG_RETURN_BOOL(false);
     279                 :           6 :                         break;
     280                 :             : 
     281                 :             :                 case INETSTRAT_EQ:
     282         [ -  + ]:           3 :                         if (gk_ip_minbits(key) != ip_bits(query))
     283                 :           0 :                                 PG_RETURN_BOOL(false);
     284                 :           3 :                         break;
     285                 :             : 
     286                 :             :                 case INETSTRAT_GE:
     287                 :             :                 case INETSTRAT_GT:
     288         [ +  + ]:          12 :                         if (gk_ip_minbits(key) > ip_bits(query))
     289                 :           6 :                                 PG_RETURN_BOOL(true);
     290         [ -  + ]:           6 :                         if (gk_ip_minbits(key) < ip_bits(query))
     291                 :           0 :                                 PG_RETURN_BOOL(false);
     292                 :           6 :                         break;
     293                 :             : 
     294                 :             :                 case INETSTRAT_NE:
     295         [ +  + ]:           6 :                         if (gk_ip_minbits(key) != ip_bits(query))
     296                 :           3 :                                 PG_RETURN_BOOL(true);
     297                 :           3 :                         break;
     298                 :             :         }
     299                 :             : 
     300                 :             :         /*
     301                 :             :          * Check 5: whole address
     302                 :             :          *
     303                 :             :          * Netmask bit counts are the same, so check all the address bits.
     304                 :             :          */
     305                 :          18 :         order = bitncmp(gk_ip_addr(key), ip_addr(query), gk_ip_maxbits(key));
     306                 :             : 
     307   [ +  +  +  +  :          18 :         switch (strategy)
                +  +  - ]
     308                 :             :         {
     309                 :             :                 case INETSTRAT_LT:
     310                 :           3 :                         PG_RETURN_BOOL(order < 0);
     311                 :             : 
     312                 :             :                 case INETSTRAT_LE:
     313                 :           3 :                         PG_RETURN_BOOL(order <= 0);
     314                 :             : 
     315                 :             :                 case INETSTRAT_EQ:
     316                 :           3 :                         PG_RETURN_BOOL(order == 0);
     317                 :             : 
     318                 :             :                 case INETSTRAT_GE:
     319                 :           3 :                         PG_RETURN_BOOL(order >= 0);
     320                 :             : 
     321                 :             :                 case INETSTRAT_GT:
     322                 :           3 :                         PG_RETURN_BOOL(order > 0);
     323                 :             : 
     324                 :             :                 case INETSTRAT_NE:
     325                 :           3 :                         PG_RETURN_BOOL(order != 0);
     326                 :             :         }
     327                 :             : 
     328   [ #  #  #  # ]:           0 :         elog(ERROR, "unknown strategy for inet GiST");
     329                 :           0 :         PG_RETURN_BOOL(false);          /* keep compiler quiet */
     330                 :         204 : }
     331                 :             : 
     332                 :             : /*
     333                 :             :  * Calculate parameters of the union of some GistInetKeys.
     334                 :             :  *
     335                 :             :  * Examine the keys in elements m..n inclusive of the GISTENTRY array,
     336                 :             :  * and compute these output parameters:
     337                 :             :  * *minfamily_p = minimum IP address family number
     338                 :             :  * *maxfamily_p = maximum IP address family number
     339                 :             :  * *minbits_p = minimum netmask width
     340                 :             :  * *commonbits_p = number of leading bits in common among the addresses
     341                 :             :  *
     342                 :             :  * minbits and commonbits are forced to zero if there's more than one
     343                 :             :  * address family.
     344                 :             :  */
     345                 :             : static void
     346                 :           0 : calc_inet_union_params(GISTENTRY *ent,
     347                 :             :                                            int m, int n,
     348                 :             :                                            int *minfamily_p,
     349                 :             :                                            int *maxfamily_p,
     350                 :             :                                            int *minbits_p,
     351                 :             :                                            int *commonbits_p)
     352                 :             : {
     353                 :           0 :         int                     minfamily,
     354                 :             :                                 maxfamily,
     355                 :             :                                 minbits,
     356                 :             :                                 commonbits;
     357                 :           0 :         unsigned char *addr;
     358                 :           0 :         GistInetKey *tmp;
     359                 :           0 :         int                     i;
     360                 :             : 
     361                 :             :         /* Must be at least one key. */
     362         [ #  # ]:           0 :         Assert(m <= n);
     363                 :             : 
     364                 :             :         /* Initialize variables using the first key. */
     365                 :           0 :         tmp = DatumGetInetKeyP(ent[m].key);
     366                 :           0 :         minfamily = maxfamily = gk_ip_family(tmp);
     367                 :           0 :         minbits = gk_ip_minbits(tmp);
     368                 :           0 :         commonbits = gk_ip_commonbits(tmp);
     369                 :           0 :         addr = gk_ip_addr(tmp);
     370                 :             : 
     371                 :             :         /* Scan remaining keys. */
     372         [ #  # ]:           0 :         for (i = m + 1; i <= n; i++)
     373                 :             :         {
     374                 :           0 :                 tmp = DatumGetInetKeyP(ent[i].key);
     375                 :             : 
     376                 :             :                 /* Determine range of family numbers */
     377         [ #  # ]:           0 :                 if (minfamily > gk_ip_family(tmp))
     378                 :           0 :                         minfamily = gk_ip_family(tmp);
     379         [ #  # ]:           0 :                 if (maxfamily < gk_ip_family(tmp))
     380                 :           0 :                         maxfamily = gk_ip_family(tmp);
     381                 :             : 
     382                 :             :                 /* Find minimum minbits */
     383         [ #  # ]:           0 :                 if (minbits > gk_ip_minbits(tmp))
     384                 :           0 :                         minbits = gk_ip_minbits(tmp);
     385                 :             : 
     386                 :             :                 /* Find minimum number of bits in common */
     387         [ #  # ]:           0 :                 if (commonbits > gk_ip_commonbits(tmp))
     388                 :           0 :                         commonbits = gk_ip_commonbits(tmp);
     389         [ #  # ]:           0 :                 if (commonbits > 0)
     390                 :           0 :                         commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits);
     391                 :           0 :         }
     392                 :             : 
     393                 :             :         /* Force minbits/commonbits to zero if more than one family. */
     394         [ #  # ]:           0 :         if (minfamily != maxfamily)
     395                 :           0 :                 minbits = commonbits = 0;
     396                 :             : 
     397                 :           0 :         *minfamily_p = minfamily;
     398                 :           0 :         *maxfamily_p = maxfamily;
     399                 :           0 :         *minbits_p = minbits;
     400                 :           0 :         *commonbits_p = commonbits;
     401                 :           0 : }
     402                 :             : 
     403                 :             : /*
     404                 :             :  * Same as above, but the GISTENTRY elements to examine are those with
     405                 :             :  * indices listed in the offsets[] array.
     406                 :             :  */
     407                 :             : static void
     408                 :           0 : calc_inet_union_params_indexed(GISTENTRY *ent,
     409                 :             :                                                            OffsetNumber *offsets, int noffsets,
     410                 :             :                                                            int *minfamily_p,
     411                 :             :                                                            int *maxfamily_p,
     412                 :             :                                                            int *minbits_p,
     413                 :             :                                                            int *commonbits_p)
     414                 :             : {
     415                 :           0 :         int                     minfamily,
     416                 :             :                                 maxfamily,
     417                 :             :                                 minbits,
     418                 :             :                                 commonbits;
     419                 :           0 :         unsigned char *addr;
     420                 :           0 :         GistInetKey *tmp;
     421                 :           0 :         int                     i;
     422                 :             : 
     423                 :             :         /* Must be at least one key. */
     424         [ #  # ]:           0 :         Assert(noffsets > 0);
     425                 :             : 
     426                 :             :         /* Initialize variables using the first key. */
     427                 :           0 :         tmp = DatumGetInetKeyP(ent[offsets[0]].key);
     428                 :           0 :         minfamily = maxfamily = gk_ip_family(tmp);
     429                 :           0 :         minbits = gk_ip_minbits(tmp);
     430                 :           0 :         commonbits = gk_ip_commonbits(tmp);
     431                 :           0 :         addr = gk_ip_addr(tmp);
     432                 :             : 
     433                 :             :         /* Scan remaining keys. */
     434         [ #  # ]:           0 :         for (i = 1; i < noffsets; i++)
     435                 :             :         {
     436                 :           0 :                 tmp = DatumGetInetKeyP(ent[offsets[i]].key);
     437                 :             : 
     438                 :             :                 /* Determine range of family numbers */
     439         [ #  # ]:           0 :                 if (minfamily > gk_ip_family(tmp))
     440                 :           0 :                         minfamily = gk_ip_family(tmp);
     441         [ #  # ]:           0 :                 if (maxfamily < gk_ip_family(tmp))
     442                 :           0 :                         maxfamily = gk_ip_family(tmp);
     443                 :             : 
     444                 :             :                 /* Find minimum minbits */
     445         [ #  # ]:           0 :                 if (minbits > gk_ip_minbits(tmp))
     446                 :           0 :                         minbits = gk_ip_minbits(tmp);
     447                 :             : 
     448                 :             :                 /* Find minimum number of bits in common */
     449         [ #  # ]:           0 :                 if (commonbits > gk_ip_commonbits(tmp))
     450                 :           0 :                         commonbits = gk_ip_commonbits(tmp);
     451         [ #  # ]:           0 :                 if (commonbits > 0)
     452                 :           0 :                         commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits);
     453                 :           0 :         }
     454                 :             : 
     455                 :             :         /* Force minbits/commonbits to zero if more than one family. */
     456         [ #  # ]:           0 :         if (minfamily != maxfamily)
     457                 :           0 :                 minbits = commonbits = 0;
     458                 :             : 
     459                 :           0 :         *minfamily_p = minfamily;
     460                 :           0 :         *maxfamily_p = maxfamily;
     461                 :           0 :         *minbits_p = minbits;
     462                 :           0 :         *commonbits_p = commonbits;
     463                 :           0 : }
     464                 :             : 
     465                 :             : /*
     466                 :             :  * Construct a GistInetKey representing a union value.
     467                 :             :  *
     468                 :             :  * Inputs are the family/minbits/commonbits values to use, plus a pointer to
     469                 :             :  * the address field of one of the union inputs.  (Since we're going to copy
     470                 :             :  * just the bits-in-common, it doesn't matter which one.)
     471                 :             :  */
     472                 :             : static GistInetKey *
     473                 :           0 : build_inet_union_key(int family, int minbits, int commonbits,
     474                 :             :                                          unsigned char *addr)
     475                 :             : {
     476                 :           0 :         GistInetKey *result;
     477                 :             : 
     478                 :             :         /* Make sure any unused bits are zeroed. */
     479                 :           0 :         result = palloc0_object(GistInetKey);
     480                 :             : 
     481                 :           0 :         gk_ip_family(result) = family;
     482                 :           0 :         gk_ip_minbits(result) = minbits;
     483                 :           0 :         gk_ip_commonbits(result) = commonbits;
     484                 :             : 
     485                 :             :         /* Clone appropriate bytes of the address. */
     486         [ #  # ]:           0 :         if (commonbits > 0)
     487                 :           0 :                 memcpy(gk_ip_addr(result), addr, (commonbits + 7) / 8);
     488                 :             : 
     489                 :             :         /* Clean any unwanted bits in the last partial byte. */
     490         [ #  # ]:           0 :         if (commonbits % 8 != 0)
     491                 :           0 :                 gk_ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));
     492                 :             : 
     493                 :             :         /* Set varlena header correctly. */
     494                 :           0 :         SET_GK_VARSIZE(result);
     495                 :             : 
     496                 :           0 :         return result;
     497                 :           0 : }
     498                 :             : 
     499                 :             : 
     500                 :             : /*
     501                 :             :  * The GiST union function
     502                 :             :  *
     503                 :             :  * See comments at head of file for the definition of the union.
     504                 :             :  */
     505                 :             : Datum
     506                 :           0 : inet_gist_union(PG_FUNCTION_ARGS)
     507                 :             : {
     508                 :           0 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     509                 :           0 :         GISTENTRY  *ent = entryvec->vector;
     510                 :           0 :         int                     minfamily,
     511                 :             :                                 maxfamily,
     512                 :             :                                 minbits,
     513                 :             :                                 commonbits;
     514                 :           0 :         unsigned char *addr;
     515                 :           0 :         GistInetKey *tmp,
     516                 :             :                            *result;
     517                 :             : 
     518                 :             :         /* Determine parameters of the union. */
     519                 :           0 :         calc_inet_union_params(ent, 0, entryvec->n - 1,
     520                 :             :                                                    &minfamily, &maxfamily,
     521                 :             :                                                    &minbits, &commonbits);
     522                 :             : 
     523                 :             :         /* If more than one family, emit family number zero. */
     524         [ #  # ]:           0 :         if (minfamily != maxfamily)
     525                 :           0 :                 minfamily = 0;
     526                 :             : 
     527                 :             :         /* Initialize address using the first key. */
     528                 :           0 :         tmp = DatumGetInetKeyP(ent[0].key);
     529                 :           0 :         addr = gk_ip_addr(tmp);
     530                 :             : 
     531                 :             :         /* Construct the union value. */
     532                 :           0 :         result = build_inet_union_key(minfamily, minbits, commonbits, addr);
     533                 :             : 
     534                 :           0 :         PG_RETURN_POINTER(result);
     535                 :           0 : }
     536                 :             : 
     537                 :             : /*
     538                 :             :  * The GiST compress function
     539                 :             :  *
     540                 :             :  * Convert an inet value to GistInetKey.
     541                 :             :  */
     542                 :             : Datum
     543                 :           0 : inet_gist_compress(PG_FUNCTION_ARGS)
     544                 :             : {
     545                 :           0 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     546                 :           0 :         GISTENTRY  *retval;
     547                 :             : 
     548         [ #  # ]:           0 :         if (entry->leafkey)
     549                 :             :         {
     550                 :           0 :                 retval = palloc_object(GISTENTRY);
     551         [ #  # ]:           0 :                 if (DatumGetPointer(entry->key) != NULL)
     552                 :             :                 {
     553                 :           0 :                         inet       *in = DatumGetInetPP(entry->key);
     554                 :           0 :                         GistInetKey *r;
     555                 :             : 
     556                 :           0 :                         r = palloc0_object(GistInetKey);
     557                 :             : 
     558                 :           0 :                         gk_ip_family(r) = ip_family(in);
     559                 :           0 :                         gk_ip_minbits(r) = ip_bits(in);
     560                 :           0 :                         gk_ip_commonbits(r) = gk_ip_maxbits(r);
     561                 :           0 :                         memcpy(gk_ip_addr(r), ip_addr(in), gk_ip_addrsize(r));
     562                 :           0 :                         SET_GK_VARSIZE(r);
     563                 :             : 
     564                 :           0 :                         gistentryinit(*retval, PointerGetDatum(r),
     565                 :             :                                                   entry->rel, entry->page,
     566                 :             :                                                   entry->offset, false);
     567                 :           0 :                 }
     568                 :             :                 else
     569                 :             :                 {
     570                 :           0 :                         gistentryinit(*retval, (Datum) 0,
     571                 :             :                                                   entry->rel, entry->page,
     572                 :             :                                                   entry->offset, false);
     573                 :             :                 }
     574                 :           0 :         }
     575                 :             :         else
     576                 :           0 :                 retval = entry;
     577                 :           0 :         PG_RETURN_POINTER(retval);
     578                 :           0 : }
     579                 :             : 
     580                 :             : /*
     581                 :             :  * We do not need a decompress function, because the other GiST inet
     582                 :             :  * support functions work with the GistInetKey representation.
     583                 :             :  */
     584                 :             : 
     585                 :             : /*
     586                 :             :  * The GiST fetch function
     587                 :             :  *
     588                 :             :  * Reconstruct the original inet datum from a GistInetKey.
     589                 :             :  */
     590                 :             : Datum
     591                 :           0 : inet_gist_fetch(PG_FUNCTION_ARGS)
     592                 :             : {
     593                 :           0 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     594                 :           0 :         GistInetKey *key = DatumGetInetKeyP(entry->key);
     595                 :           0 :         GISTENTRY  *retval;
     596                 :           0 :         inet       *dst;
     597                 :             : 
     598                 :           0 :         dst = palloc0_object(inet);
     599                 :             : 
     600                 :           0 :         ip_family(dst) = gk_ip_family(key);
     601                 :           0 :         ip_bits(dst) = gk_ip_minbits(key);
     602                 :           0 :         memcpy(ip_addr(dst), gk_ip_addr(key), ip_addrsize(dst));
     603                 :           0 :         SET_INET_VARSIZE(dst);
     604                 :             : 
     605                 :           0 :         retval = palloc_object(GISTENTRY);
     606                 :           0 :         gistentryinit(*retval, InetPGetDatum(dst), entry->rel, entry->page,
     607                 :             :                                   entry->offset, false);
     608                 :             : 
     609                 :           0 :         PG_RETURN_POINTER(retval);
     610                 :           0 : }
     611                 :             : 
     612                 :             : /*
     613                 :             :  * The GiST page split penalty function
     614                 :             :  *
     615                 :             :  * Charge a large penalty if address family doesn't match, or a somewhat
     616                 :             :  * smaller one if the new value would degrade the union's minbits
     617                 :             :  * (minimum netmask width).  Otherwise, penalty is inverse of the
     618                 :             :  * new number of common address bits.
     619                 :             :  */
     620                 :             : Datum
     621                 :           0 : inet_gist_penalty(PG_FUNCTION_ARGS)
     622                 :             : {
     623                 :           0 :         GISTENTRY  *origent = (GISTENTRY *) PG_GETARG_POINTER(0);
     624                 :           0 :         GISTENTRY  *newent = (GISTENTRY *) PG_GETARG_POINTER(1);
     625                 :           0 :         float      *penalty = (float *) PG_GETARG_POINTER(2);
     626                 :           0 :         GistInetKey *orig = DatumGetInetKeyP(origent->key),
     627                 :           0 :                            *new = DatumGetInetKeyP(newent->key);
     628                 :           0 :         int                     commonbits;
     629                 :             : 
     630         [ #  # ]:           0 :         if (gk_ip_family(orig) == gk_ip_family(new))
     631                 :             :         {
     632         [ #  # ]:           0 :                 if (gk_ip_minbits(orig) <= gk_ip_minbits(new))
     633                 :             :                 {
     634                 :           0 :                         commonbits = bitncommon(gk_ip_addr(orig), gk_ip_addr(new),
     635         [ #  # ]:           0 :                                                                         Min(gk_ip_commonbits(orig),
     636                 :             :                                                                                 gk_ip_commonbits(new)));
     637         [ #  # ]:           0 :                         if (commonbits > 0)
     638                 :           0 :                                 *penalty = 1.0f / commonbits;
     639                 :             :                         else
     640                 :           0 :                                 *penalty = 2;
     641                 :           0 :                 }
     642                 :             :                 else
     643                 :           0 :                         *penalty = 3;
     644                 :           0 :         }
     645                 :             :         else
     646                 :           0 :                 *penalty = 4;
     647                 :             : 
     648                 :           0 :         PG_RETURN_POINTER(penalty);
     649                 :           0 : }
     650                 :             : 
     651                 :             : /*
     652                 :             :  * The GiST PickSplit method
     653                 :             :  *
     654                 :             :  * There are two ways to split. First one is to split by address families,
     655                 :             :  * if there are multiple families appearing in the input.
     656                 :             :  *
     657                 :             :  * The second and more common way is to split by addresses. To achieve this,
     658                 :             :  * determine the number of leading bits shared by all the keys, then split on
     659                 :             :  * the next bit.  (We don't currently consider the netmask widths while doing
     660                 :             :  * this; should we?)  If we fail to get a nontrivial split that way, split
     661                 :             :  * 50-50.
     662                 :             :  */
     663                 :             : Datum
     664                 :           0 : inet_gist_picksplit(PG_FUNCTION_ARGS)
     665                 :             : {
     666                 :           0 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     667                 :           0 :         GIST_SPLITVEC *splitvec = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     668                 :           0 :         GISTENTRY  *ent = entryvec->vector;
     669                 :           0 :         int                     minfamily,
     670                 :             :                                 maxfamily,
     671                 :             :                                 minbits,
     672                 :             :                                 commonbits;
     673                 :           0 :         unsigned char *addr;
     674                 :           0 :         GistInetKey *tmp,
     675                 :             :                            *left_union,
     676                 :             :                            *right_union;
     677                 :           0 :         int                     maxoff,
     678                 :             :                                 nbytes;
     679                 :           0 :         OffsetNumber i,
     680                 :             :                            *left,
     681                 :             :                            *right;
     682                 :             : 
     683                 :           0 :         maxoff = entryvec->n - 1;
     684                 :           0 :         nbytes = (maxoff + 1) * sizeof(OffsetNumber);
     685                 :             : 
     686                 :           0 :         left = (OffsetNumber *) palloc(nbytes);
     687                 :           0 :         right = (OffsetNumber *) palloc(nbytes);
     688                 :             : 
     689                 :           0 :         splitvec->spl_left = left;
     690                 :           0 :         splitvec->spl_right = right;
     691                 :             : 
     692                 :           0 :         splitvec->spl_nleft = 0;
     693                 :           0 :         splitvec->spl_nright = 0;
     694                 :             : 
     695                 :             :         /* Determine parameters of the union of all the inputs. */
     696                 :           0 :         calc_inet_union_params(ent, FirstOffsetNumber, maxoff,
     697                 :             :                                                    &minfamily, &maxfamily,
     698                 :             :                                                    &minbits, &commonbits);
     699                 :             : 
     700         [ #  # ]:           0 :         if (minfamily != maxfamily)
     701                 :             :         {
     702                 :             :                 /* Multiple families, so split by family. */
     703         [ #  # ]:           0 :                 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     704                 :             :                 {
     705                 :             :                         /*
     706                 :             :                          * If there's more than 2 families, all but maxfamily go into the
     707                 :             :                          * left union.  This could only happen if the inputs include some
     708                 :             :                          * IPv4, some IPv6, and some already-multiple-family unions.
     709                 :             :                          */
     710                 :           0 :                         tmp = DatumGetInetKeyP(ent[i].key);
     711         [ #  # ]:           0 :                         if (gk_ip_family(tmp) != maxfamily)
     712                 :           0 :                                 left[splitvec->spl_nleft++] = i;
     713                 :             :                         else
     714                 :           0 :                                 right[splitvec->spl_nright++] = i;
     715                 :           0 :                 }
     716                 :           0 :         }
     717                 :             :         else
     718                 :             :         {
     719                 :             :                 /*
     720                 :             :                  * Split on the next bit after the common bits.  If that yields a
     721                 :             :                  * trivial split, try the next bit position to the right.  Repeat till
     722                 :             :                  * success; or if we run out of bits, do an arbitrary 50-50 split.
     723                 :             :                  */
     724                 :           0 :                 int                     maxbits = ip_family_maxbits(minfamily);
     725                 :             : 
     726         [ #  # ]:           0 :                 while (commonbits < maxbits)
     727                 :             :                 {
     728                 :             :                         /* Split using the commonbits'th bit position. */
     729                 :           0 :                         int                     bitbyte = commonbits / 8;
     730                 :           0 :                         int                     bitmask = 0x80 >> (commonbits % 8);
     731                 :             : 
     732                 :           0 :                         splitvec->spl_nleft = splitvec->spl_nright = 0;
     733                 :             : 
     734         [ #  # ]:           0 :                         for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     735                 :             :                         {
     736                 :           0 :                                 tmp = DatumGetInetKeyP(ent[i].key);
     737                 :           0 :                                 addr = gk_ip_addr(tmp);
     738         [ #  # ]:           0 :                                 if ((addr[bitbyte] & bitmask) == 0)
     739                 :           0 :                                         left[splitvec->spl_nleft++] = i;
     740                 :             :                                 else
     741                 :           0 :                                         right[splitvec->spl_nright++] = i;
     742                 :           0 :                         }
     743                 :             : 
     744   [ #  #  #  # ]:           0 :                         if (splitvec->spl_nleft > 0 && splitvec->spl_nright > 0)
     745                 :           0 :                                 break;                  /* success */
     746                 :           0 :                         commonbits++;
     747      [ #  #  # ]:           0 :                 }
     748                 :             : 
     749         [ #  # ]:           0 :                 if (commonbits >= maxbits)
     750                 :             :                 {
     751                 :             :                         /* Failed ... do a 50-50 split. */
     752                 :           0 :                         splitvec->spl_nleft = splitvec->spl_nright = 0;
     753                 :             : 
     754         [ #  # ]:           0 :                         for (i = FirstOffsetNumber; i <= maxoff / 2; i = OffsetNumberNext(i))
     755                 :             :                         {
     756                 :           0 :                                 left[splitvec->spl_nleft++] = i;
     757                 :           0 :                         }
     758         [ #  # ]:           0 :                         for (; i <= maxoff; i = OffsetNumberNext(i))
     759                 :             :                         {
     760                 :           0 :                                 right[splitvec->spl_nright++] = i;
     761                 :           0 :                         }
     762                 :           0 :                 }
     763                 :           0 :         }
     764                 :             : 
     765                 :             :         /*
     766                 :             :          * Compute the union value for each side from scratch.  In most cases we
     767                 :             :          * could approximate the union values with what we already know, but this
     768                 :             :          * ensures that each side has minbits and commonbits set as high as
     769                 :             :          * possible.
     770                 :             :          */
     771                 :           0 :         calc_inet_union_params_indexed(ent, left, splitvec->spl_nleft,
     772                 :             :                                                                    &minfamily, &maxfamily,
     773                 :             :                                                                    &minbits, &commonbits);
     774         [ #  # ]:           0 :         if (minfamily != maxfamily)
     775                 :           0 :                 minfamily = 0;
     776                 :           0 :         tmp = DatumGetInetKeyP(ent[left[0]].key);
     777                 :           0 :         addr = gk_ip_addr(tmp);
     778                 :           0 :         left_union = build_inet_union_key(minfamily, minbits, commonbits, addr);
     779                 :           0 :         splitvec->spl_ldatum = PointerGetDatum(left_union);
     780                 :             : 
     781                 :           0 :         calc_inet_union_params_indexed(ent, right, splitvec->spl_nright,
     782                 :             :                                                                    &minfamily, &maxfamily,
     783                 :             :                                                                    &minbits, &commonbits);
     784         [ #  # ]:           0 :         if (minfamily != maxfamily)
     785                 :           0 :                 minfamily = 0;
     786                 :           0 :         tmp = DatumGetInetKeyP(ent[right[0]].key);
     787                 :           0 :         addr = gk_ip_addr(tmp);
     788                 :           0 :         right_union = build_inet_union_key(minfamily, minbits, commonbits, addr);
     789                 :           0 :         splitvec->spl_rdatum = PointerGetDatum(right_union);
     790                 :             : 
     791                 :           0 :         PG_RETURN_POINTER(splitvec);
     792                 :           0 : }
     793                 :             : 
     794                 :             : /*
     795                 :             :  * The GiST equality function
     796                 :             :  */
     797                 :             : Datum
     798                 :           0 : inet_gist_same(PG_FUNCTION_ARGS)
     799                 :             : {
     800                 :           0 :         GistInetKey *left = DatumGetInetKeyP(PG_GETARG_DATUM(0));
     801                 :           0 :         GistInetKey *right = DatumGetInetKeyP(PG_GETARG_DATUM(1));
     802                 :           0 :         bool       *result = (bool *) PG_GETARG_POINTER(2);
     803                 :             : 
     804         [ #  # ]:           0 :         *result = (gk_ip_family(left) == gk_ip_family(right) &&
     805         [ #  # ]:           0 :                            gk_ip_minbits(left) == gk_ip_minbits(right) &&
     806         [ #  # ]:           0 :                            gk_ip_commonbits(left) == gk_ip_commonbits(right) &&
     807                 :           0 :                            memcmp(gk_ip_addr(left), gk_ip_addr(right),
     808                 :           0 :                                           gk_ip_addrsize(left)) == 0);
     809                 :             : 
     810                 :           0 :         PG_RETURN_POINTER(result);
     811                 :           0 : }
        

Generated by: LCOV version 2.3.2-1