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