PostgreSQL Source Code git master
Loading...
Searching...
No Matches
network_spgist.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * network_spgist.c
4 * SP-GiST support for network types.
5 *
6 * We split inet index entries first by address family (IPv4 or IPv6).
7 * If the entries below a given inner tuple are all of the same family,
8 * we identify their common prefix and split by the next bit of the address,
9 * and by whether their masklens exceed the length of the common prefix.
10 *
11 * An inner tuple that has both IPv4 and IPv6 children has a null prefix
12 * and exactly two nodes, the first being for IPv4 and the second for IPv6.
13 *
14 * Otherwise, the prefix is a CIDR value representing the common prefix,
15 * and there are exactly four nodes. Node numbers 0 and 1 are for addresses
16 * with the same masklen as the prefix, while node numbers 2 and 3 are for
17 * addresses with larger masklen. (We do not allow a tuple to contain
18 * entries with masklen smaller than its prefix's.) Node numbers 0 and 1
19 * are distinguished by the next bit of the address after the common prefix,
20 * and likewise for node numbers 2 and 3. If there are no more bits in
21 * the address family, everything goes into node 0 (which will probably
22 * lead to creating an allTheSame tuple).
23 *
24 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
25 * Portions Copyright (c) 1994, Regents of the University of California
26 *
27 * IDENTIFICATION
28 * src/backend/utils/adt/network_spgist.c
29 *
30 *-------------------------------------------------------------------------
31 */
32#include "postgres.h"
33
34#include <sys/socket.h>
35
36#include "access/spgist.h"
37#include "catalog/pg_type.h"
38#include "utils/fmgrprotos.h"
39#include "utils/inet.h"
40#include "varatt.h"
41
42
43static int inet_spg_node_number(const inet *val, int commonbits);
44static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys,
45 ScanKey scankeys, bool leaf);
46
47/*
48 * The SP-GiST configuration function
49 */
52{
53#ifdef NOT_USED
55#endif
57
58 cfg->prefixType = CIDROID;
59 cfg->labelType = VOIDOID;
60 cfg->canReturnData = true;
61 cfg->longValuesOK = false;
62
64}
65
66/*
67 * The SP-GiST choose function
68 */
71{
75 *prefix;
76 int commonbits;
77
78 /*
79 * If we're looking at a tuple that splits by address family, choose the
80 * appropriate subnode.
81 */
82 if (!in->hasPrefix)
83 {
84 /* allTheSame isn't possible for such a tuple */
85 Assert(!in->allTheSame);
86 Assert(in->nNodes == 2);
87
89 out->result.matchNode.nodeN = (ip_family(val) == PGSQL_AF_INET) ? 0 : 1;
91
93 }
94
95 /* Else it must split by prefix */
96 Assert(in->nNodes == 4 || in->allTheSame);
97
98 prefix = DatumGetInetPP(in->prefixDatum);
99 commonbits = ip_bits(prefix);
100
101 /*
102 * We cannot put addresses from different families under the same inner
103 * node, so we have to split if the new value's family is different.
104 */
105 if (ip_family(val) != ip_family(prefix))
106 {
107 /* Set up 2-node tuple */
109 out->result.splitTuple.prefixHasPrefix = false;
112
113 /* Identify which node the existing data goes into */
115 (ip_family(prefix) == PGSQL_AF_INET) ? 0 : 1;
116
119
121 }
122
123 /*
124 * If the new value does not match the existing prefix, we have to split.
125 */
126 if (ip_bits(val) < commonbits ||
127 bitncmp(ip_addr(prefix), ip_addr(val), commonbits) != 0)
128 {
129 /* Determine new prefix length for the split tuple */
130 commonbits = bitncommon(ip_addr(prefix), ip_addr(val),
131 Min(ip_bits(val), commonbits));
132
133 /* Set up 4-node tuple */
140
141 /* Identify which node the existing data goes into */
143 inet_spg_node_number(prefix, commonbits);
144
147
149 }
150
151 /*
152 * All OK, choose the node to descend into. (If this tuple is marked
153 * allTheSame, the core code will ignore our choice of nodeN; but we need
154 * not account for that case explicitly here.)
155 */
157 out->result.matchNode.nodeN = inet_spg_node_number(val, commonbits);
159
161}
162
163/*
164 * The GiST PickSplit method
165 */
166Datum
168{
171 inet *prefix,
172 *tmp;
173 int i,
174 commonbits;
175 bool differentFamilies = false;
176
177 /* Initialize the prefix with the first item */
178 prefix = DatumGetInetPP(in->datums[0]);
179 commonbits = ip_bits(prefix);
180
181 /* Examine remaining items to discover minimum common prefix length */
182 for (i = 1; i < in->nTuples; i++)
183 {
184 tmp = DatumGetInetPP(in->datums[i]);
185
186 if (ip_family(tmp) != ip_family(prefix))
187 {
188 differentFamilies = true;
189 break;
190 }
191
192 if (ip_bits(tmp) < commonbits)
193 commonbits = ip_bits(tmp);
194 commonbits = bitncommon(ip_addr(prefix), ip_addr(tmp), commonbits);
195 if (commonbits == 0)
196 break;
197 }
198
199 /* Don't need labels; allocate output arrays */
200 out->nodeLabels = NULL;
201 out->mapTuplesToNodes = palloc_array(int, in->nTuples);
203
205 {
206 /* Set up 2-node tuple */
207 out->hasPrefix = false;
208 out->nNodes = 2;
209
210 for (i = 0; i < in->nTuples; i++)
211 {
212 tmp = DatumGetInetPP(in->datums[i]);
213 out->mapTuplesToNodes[i] =
214 (ip_family(tmp) == PGSQL_AF_INET) ? 0 : 1;
215 out->leafTupleDatums[i] = InetPGetDatum(tmp);
216 }
217 }
218 else
219 {
220 /* Set up 4-node tuple */
221 out->hasPrefix = true;
222 out->prefixDatum =
223 InetPGetDatum(cidr_set_masklen_internal(prefix, commonbits));
224 out->nNodes = 4;
225
226 for (i = 0; i < in->nTuples; i++)
227 {
228 tmp = DatumGetInetPP(in->datums[i]);
229 out->mapTuplesToNodes[i] = inet_spg_node_number(tmp, commonbits);
230 out->leafTupleDatums[i] = InetPGetDatum(tmp);
231 }
232 }
233
235}
236
237/*
238 * The SP-GiST query consistency check for inner tuples
239 */
240Datum
242{
245 int i;
246 int which;
247
248 if (!in->hasPrefix)
249 {
250 Assert(!in->allTheSame);
251 Assert(in->nNodes == 2);
252
253 /* Identify which child nodes need to be visited */
254 which = 1 | (1 << 1);
255
256 for (i = 0; i < in->nkeys; i++)
257 {
258 StrategyNumber strategy = in->scankeys[i].sk_strategy;
260
261 switch (strategy)
262 {
266 which &= 1;
267 break;
268
272 which &= (1 << 1);
273 break;
274
276 break;
277
278 default:
279 /* all other ops can only match addrs of same family */
281 which &= 1;
282 else
283 which &= (1 << 1);
284 break;
285 }
286 }
287 }
288 else if (!in->allTheSame)
289 {
290 Assert(in->nNodes == 4);
291
292 /* Identify which child nodes need to be visited */
294 in->nkeys, in->scankeys, false);
295 }
296 else
297 {
298 /* Must visit all nodes; we assume there are less than 32 of 'em */
299 which = ~0;
300 }
301
302 out->nNodes = 0;
303
304 if (which)
305 {
306 out->nodeNumbers = palloc_array(int, in->nNodes);
307
308 for (i = 0; i < in->nNodes; i++)
309 {
310 if (which & (1 << i))
311 {
312 out->nodeNumbers[out->nNodes] = i;
313 out->nNodes++;
314 }
315 }
316 }
317
319}
320
321/*
322 * The SP-GiST query consistency check for leaf tuples
323 */
324Datum
326{
330
331 /* All tests are exact. */
332 out->recheck = false;
333
334 /* Leaf is what it is... */
336
337 /* Use common code to apply the tests. */
339 true));
340}
341
342/*
343 * Calculate node number (within a 4-node, single-family inner index tuple)
344 *
345 * The value must have the same family as the node's prefix, and
346 * commonbits is the mask length of the prefix. We use even or odd
347 * nodes according to the next address bit after the commonbits,
348 * and low or high nodes according to whether the value's mask length
349 * is larger than commonbits.
350 */
351static int
352inet_spg_node_number(const inet *val, int commonbits)
353{
354 int nodeN = 0;
355
356 if (commonbits < ip_maxbits(val) &&
357 ip_addr(val)[commonbits / 8] & (1 << (7 - commonbits % 8)))
358 nodeN |= 1;
359 if (commonbits < ip_bits(val))
360 nodeN |= 2;
361
362 return nodeN;
363}
364
365/*
366 * Calculate bitmap of node numbers that are consistent with the query
367 *
368 * This can be used either at a 4-way inner tuple, or at a leaf tuple.
369 * In the latter case, we should return a boolean result (0 or 1)
370 * not a bitmap.
371 *
372 * This definition is pretty odd, but the inner and leaf consistency checks
373 * are mostly common and it seems best to keep them in one function.
374 */
375static int
376inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys,
377 bool leaf)
378{
379 int bitmap;
380 int commonbits,
381 i;
382
383 /* Initialize result to allow visiting all children */
384 if (leaf)
385 bitmap = 1;
386 else
387 bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3);
388
389 commonbits = ip_bits(prefix);
390
391 for (i = 0; i < nkeys; i++)
392 {
393 inet *argument = DatumGetInetPP(scankeys[i].sk_argument);
394 StrategyNumber strategy = scankeys[i].sk_strategy;
395 int order;
396
397 /*
398 * Check 0: different families
399 *
400 * Matching families do not help any of the strategies.
401 */
402 if (ip_family(argument) != ip_family(prefix))
403 {
404 switch (strategy)
405 {
408 if (ip_family(argument) < ip_family(prefix))
409 bitmap = 0;
410 break;
411
414 if (ip_family(argument) > ip_family(prefix))
415 bitmap = 0;
416 break;
417
419 break;
420
421 default:
422 /* For all other cases, we can be sure there is no match */
423 bitmap = 0;
424 break;
425 }
426
427 if (!bitmap)
428 break;
429
430 /* Other checks make no sense with different families. */
431 continue;
432 }
433
434 /*
435 * Check 1: network bit count
436 *
437 * Network bit count (ip_bits) helps to check leaves for sub network
438 * and sup network operators. At non-leaf nodes, we know every child
439 * value has greater ip_bits, so we can avoid descending in some cases
440 * too.
441 *
442 * This check is less expensive than checking the address bits, so we
443 * are doing this before, but it has to be done after for the basic
444 * comparison strategies, because ip_bits only affect their results
445 * when the common network bits are the same.
446 */
447 switch (strategy)
448 {
450 if (commonbits <= ip_bits(argument))
451 bitmap &= (1 << 2) | (1 << 3);
452 break;
453
455 if (commonbits < ip_bits(argument))
456 bitmap &= (1 << 2) | (1 << 3);
457 break;
458
460 if (commonbits == ip_bits(argument) - 1)
461 bitmap &= 1 | (1 << 1);
462 else if (commonbits >= ip_bits(argument))
463 bitmap = 0;
464 break;
465
467 if (commonbits == ip_bits(argument))
468 bitmap &= 1 | (1 << 1);
469 else if (commonbits > ip_bits(argument))
470 bitmap = 0;
471 break;
472
474 if (commonbits < ip_bits(argument))
475 bitmap &= (1 << 2) | (1 << 3);
476 else if (commonbits == ip_bits(argument))
477 bitmap &= 1 | (1 << 1);
478 else
479 bitmap = 0;
480 break;
481 }
482
483 if (!bitmap)
484 break;
485
486 /*
487 * Check 2: common network bits
488 *
489 * Compare available common prefix bits to the query, but not beyond
490 * either the query's netmask or the minimum netmask among the
491 * represented values. If these bits don't match the query, we can
492 * eliminate some cases.
493 */
494 order = bitncmp(ip_addr(prefix), ip_addr(argument),
495 Min(commonbits, ip_bits(argument)));
496
497 if (order != 0)
498 {
499 switch (strategy)
500 {
503 if (order > 0)
504 bitmap = 0;
505 break;
506
509 if (order < 0)
510 bitmap = 0;
511 break;
512
514 break;
515
516 default:
517 /* For all other cases, we can be sure there is no match */
518 bitmap = 0;
519 break;
520 }
521
522 if (!bitmap)
523 break;
524
525 /*
526 * Remaining checks make no sense when common bits don't match.
527 */
528 continue;
529 }
530
531 /*
532 * Check 3: next network bit
533 *
534 * We can filter out branch 2 or 3 using the next network bit of the
535 * argument, if it is available.
536 *
537 * This check matters for the performance of the search. The results
538 * would be correct without it.
539 */
540 if (bitmap & ((1 << 2) | (1 << 3)) &&
541 commonbits < ip_bits(argument))
542 {
543 int nextbit;
544
545 nextbit = ip_addr(argument)[commonbits / 8] &
546 (1 << (7 - commonbits % 8));
547
548 switch (strategy)
549 {
552 if (!nextbit)
553 bitmap &= 1 | (1 << 1) | (1 << 2);
554 break;
555
558 if (nextbit)
559 bitmap &= 1 | (1 << 1) | (1 << 3);
560 break;
561
563 break;
564
565 default:
566 if (!nextbit)
567 bitmap &= 1 | (1 << 1) | (1 << 2);
568 else
569 bitmap &= 1 | (1 << 1) | (1 << 3);
570 break;
571 }
572
573 if (!bitmap)
574 break;
575 }
576
577 /*
578 * Remaining checks are only for the basic comparison strategies. This
579 * test relies on the strategy number ordering defined in stratnum.h.
580 */
581 if (strategy < RTEqualStrategyNumber ||
583 continue;
584
585 /*
586 * Check 4: network bit count
587 *
588 * At this point, we know that the common network bits of the prefix
589 * and the argument are the same, so we can go forward and check the
590 * ip_bits.
591 */
592 switch (strategy)
593 {
596 if (commonbits == ip_bits(argument))
597 bitmap &= 1 | (1 << 1);
598 else if (commonbits > ip_bits(argument))
599 bitmap = 0;
600 break;
601
604 if (commonbits < ip_bits(argument))
605 bitmap &= (1 << 2) | (1 << 3);
606 break;
607 }
608
609 if (!bitmap)
610 break;
611
612 /* Remaining checks don't make sense with different ip_bits. */
613 if (commonbits != ip_bits(argument))
614 continue;
615
616 /*
617 * Check 5: next host bit
618 *
619 * We can filter out branch 0 or 1 using the next host bit of the
620 * argument, if it is available.
621 *
622 * This check matters for the performance of the search. The results
623 * would be correct without it. There is no point in running it for
624 * leafs as we have to check the whole address on the next step.
625 */
626 if (!leaf && bitmap & (1 | (1 << 1)) &&
627 commonbits < ip_maxbits(argument))
628 {
629 int nextbit;
630
631 nextbit = ip_addr(argument)[commonbits / 8] &
632 (1 << (7 - commonbits % 8));
633
634 switch (strategy)
635 {
638 if (!nextbit)
639 bitmap &= 1 | (1 << 2) | (1 << 3);
640 break;
641
644 if (nextbit)
645 bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
646 break;
647
649 break;
650
651 default:
652 if (!nextbit)
653 bitmap &= 1 | (1 << 2) | (1 << 3);
654 else
655 bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
656 break;
657 }
658
659 if (!bitmap)
660 break;
661 }
662
663 /*
664 * Check 6: whole address
665 *
666 * This is the last check for correctness of the basic comparison
667 * strategies. It's only appropriate at leaf entries.
668 */
669 if (leaf)
670 {
671 /* Redo ordering comparison using all address bits */
672 order = bitncmp(ip_addr(prefix), ip_addr(argument),
673 ip_maxbits(prefix));
674
675 switch (strategy)
676 {
678 if (order >= 0)
679 bitmap = 0;
680 break;
681
683 if (order > 0)
684 bitmap = 0;
685 break;
686
688 if (order != 0)
689 bitmap = 0;
690 break;
691
693 if (order < 0)
694 bitmap = 0;
695 break;
696
698 if (order <= 0)
699 bitmap = 0;
700 break;
701
703 if (order == 0)
704 bitmap = 0;
705 break;
706 }
707
708 if (!bitmap)
709 break;
710 }
711 }
712
713 return bitmap;
714}
#define Min(x, y)
Definition c.h:997
#define Assert(condition)
Definition c.h:873
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
long val
Definition informix.c:689
int i
Definition isn.c:77
int bitncommon(const unsigned char *l, const unsigned char *r, int n)
Definition network.c:1536
inet * cidr_set_masklen_internal(const inet *src, int bits)
Definition network.c:364
int bitncmp(const unsigned char *l, const unsigned char *r, int n)
Definition network.c:1502
Datum inet_spg_config(PG_FUNCTION_ARGS)
Datum inet_spg_choose(PG_FUNCTION_ARGS)
Datum inet_spg_leaf_consistent(PG_FUNCTION_ARGS)
Datum inet_spg_inner_consistent(PG_FUNCTION_ARGS)
static int inet_spg_node_number(const inet *val, int commonbits)
static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys, bool leaf)
Datum inet_spg_picksplit(PG_FUNCTION_ARGS)
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
@ spgMatchNode
Definition spgist.h:69
@ spgSplitTuple
Definition spgist.h:71
#define RTNotEqualStrategyNumber
Definition stratnum.h:69
#define RTSubStrategyNumber
Definition stratnum.h:74
uint16 StrategyNumber
Definition stratnum.h:22
#define RTSubEqualStrategyNumber
Definition stratnum.h:75
#define RTSuperEqualStrategyNumber
Definition stratnum.h:77
#define RTEqualStrategyNumber
Definition stratnum.h:68
#define RTLessEqualStrategyNumber
Definition stratnum.h:71
#define RTGreaterEqualStrategyNumber
Definition stratnum.h:73
#define RTGreaterStrategyNumber
Definition stratnum.h:72
#define RTSuperStrategyNumber
Definition stratnum.h:76
#define RTLessStrategyNumber
Definition stratnum.h:70
Datum sk_argument
Definition skey.h:72
StrategyNumber sk_strategy
Definition skey.h:68
Definition inet.h:53
bool hasPrefix
Definition spgist.h:61
Datum prefixDatum
Definition spgist.h:62
int nNodes
Definition spgist.h:63
Datum datum
Definition spgist.h:55
bool allTheSame
Definition spgist.h:60
bool postfixHasPrefix
Definition spgist.h:101
int childNodeN
Definition spgist.h:98
spgChooseResultType resultType
Definition spgist.h:76
struct spgChooseOut::@54::@57 splitTuple
Datum * prefixNodeLabels
Definition spgist.h:96
Datum postfixPrefixDatum
Definition spgist.h:102
Datum restDatum
Definition spgist.h:83
int prefixNNodes
Definition spgist.h:95
int nodeN
Definition spgist.h:81
union spgChooseOut::@54 result
Datum prefixPrefixDatum
Definition spgist.h:94
bool prefixHasPrefix
Definition spgist.h:93
struct spgChooseOut::@54::@55 matchNode
bool longValuesOK
Definition spgist.h:47
bool canReturnData
Definition spgist.h:46
Oid labelType
Definition spgist.h:44
Oid prefixType
Definition spgist.h:43
Datum * datums
Definition spgist.h:113
int * mapTuplesToNodes
Definition spgist.h:125
Datum * nodeLabels
Definition spgist.h:123
Datum * leafTupleDatums
Definition spgist.h:126
Datum prefixDatum
Definition spgist.h:120
static Datum InetPGetDatum(const inet *X)
Definition inet.h:129
static inet * DatumGetInetPP(Datum X)
Definition inet.h:123
#define ip_addr(inetptr)
Definition inet.h:77
#define ip_family(inetptr)
Definition inet.h:71
#define PGSQL_AF_INET
Definition inet.h:39
#define PGSQL_AF_INET6
Definition inet.h:40
#define ip_maxbits(inetptr)
Definition inet.h:83
#define ip_bits(inetptr)
Definition inet.h:74