1 /*-------------------------------------------------------------------------
4 * SP-GiST support for network types.
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.
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.
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).
24 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
25 * Portions Copyright (c) 1994, Regents of the University of California
28 * src/backend/utils/adt/network_spgist.c
30 *-------------------------------------------------------------------------
34 #include <sys/socket.h>
36 #include "access/spgist.h"
37 #include "catalog/pg_type.h"
38 #include "utils/builtins.h"
39 #include "utils/inet.h"
42 static int inet_spg_node_number(const inet
*val
, int commonbits
);
43 static int inet_spg_consistent_bitmap(const inet
*prefix
, int nkeys
,
44 ScanKey scankeys
, bool leaf
);
47 * The SP-GiST configuration function
50 inet_spg_config(PG_FUNCTION_ARGS
)
52 /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
53 spgConfigOut
*cfg
= (spgConfigOut
*) PG_GETARG_POINTER(1);
55 cfg
->prefixType
= CIDROID
;
56 cfg
->labelType
= VOIDOID
;
57 cfg
->canReturnData
= true;
58 cfg
->longValuesOK
= false;
64 * The SP-GiST choose function
67 inet_spg_choose(PG_FUNCTION_ARGS
)
69 spgChooseIn
*in
= (spgChooseIn
*) PG_GETARG_POINTER(0);
70 spgChooseOut
*out
= (spgChooseOut
*) PG_GETARG_POINTER(1);
71 inet
*val
= DatumGetInetPP(in
->datum
),
76 * If we're looking at a tuple that splits by address family, choose the
77 * appropriate subnode.
81 /* allTheSame isn't possible for such a tuple */
82 Assert(!in
->allTheSame
);
83 Assert(in
->nNodes
== 2);
85 out
->resultType
= spgMatchNode
;
86 out
->result
.matchNode
.nodeN
= (ip_family(val
) == PGSQL_AF_INET
) ? 0 : 1;
87 out
->result
.matchNode
.restDatum
= InetPGetDatum(val
);
92 /* Else it must split by prefix */
93 Assert(in
->nNodes
== 4 || in
->allTheSame
);
95 prefix
= DatumGetInetPP(in
->prefixDatum
);
96 commonbits
= ip_bits(prefix
);
99 * We cannot put addresses from different families under the same inner
100 * node, so we have to split if the new value's family is different.
102 if (ip_family(val
) != ip_family(prefix
))
104 /* Set up 2-node tuple */
105 out
->resultType
= spgSplitTuple
;
106 out
->result
.splitTuple
.prefixHasPrefix
= false;
107 out
->result
.splitTuple
.prefixNNodes
= 2;
108 out
->result
.splitTuple
.prefixNodeLabels
= NULL
;
110 /* Identify which node the existing data goes into */
111 out
->result
.splitTuple
.childNodeN
=
112 (ip_family(prefix
) == PGSQL_AF_INET
) ? 0 : 1;
114 out
->result
.splitTuple
.postfixHasPrefix
= true;
115 out
->result
.splitTuple
.postfixPrefixDatum
= InetPGetDatum(prefix
);
121 * If the new value does not match the existing prefix, we have to split.
123 if (ip_bits(val
) < commonbits
||
124 bitncmp(ip_addr(prefix
), ip_addr(val
), commonbits
) != 0)
126 /* Determine new prefix length for the split tuple */
127 commonbits
= bitncommon(ip_addr(prefix
), ip_addr(val
),
128 Min(ip_bits(val
), commonbits
));
130 /* Set up 4-node tuple */
131 out
->resultType
= spgSplitTuple
;
132 out
->result
.splitTuple
.prefixHasPrefix
= true;
133 out
->result
.splitTuple
.prefixPrefixDatum
=
134 InetPGetDatum(cidr_set_masklen_internal(val
, commonbits
));
135 out
->result
.splitTuple
.prefixNNodes
= 4;
136 out
->result
.splitTuple
.prefixNodeLabels
= NULL
;
138 /* Identify which node the existing data goes into */
139 out
->result
.splitTuple
.childNodeN
=
140 inet_spg_node_number(prefix
, commonbits
);
142 out
->result
.splitTuple
.postfixHasPrefix
= true;
143 out
->result
.splitTuple
.postfixPrefixDatum
= InetPGetDatum(prefix
);
149 * All OK, choose the node to descend into. (If this tuple is marked
150 * allTheSame, the core code will ignore our choice of nodeN; but we need
151 * not account for that case explicitly here.)
153 out
->resultType
= spgMatchNode
;
154 out
->result
.matchNode
.nodeN
= inet_spg_node_number(val
, commonbits
);
155 out
->result
.matchNode
.restDatum
= InetPGetDatum(val
);
161 * The GiST PickSplit method
164 inet_spg_picksplit(PG_FUNCTION_ARGS
)
166 spgPickSplitIn
*in
= (spgPickSplitIn
*) PG_GETARG_POINTER(0);
167 spgPickSplitOut
*out
= (spgPickSplitOut
*) PG_GETARG_POINTER(1);
172 bool differentFamilies
= false;
174 /* Initialize the prefix with the first item */
175 prefix
= DatumGetInetPP(in
->datums
[0]);
176 commonbits
= ip_bits(prefix
);
178 /* Examine remaining items to discover minimum common prefix length */
179 for (i
= 1; i
< in
->nTuples
; i
++)
181 tmp
= DatumGetInetPP(in
->datums
[i
]);
183 if (ip_family(tmp
) != ip_family(prefix
))
185 differentFamilies
= true;
189 if (ip_bits(tmp
) < commonbits
)
190 commonbits
= ip_bits(tmp
);
191 commonbits
= bitncommon(ip_addr(prefix
), ip_addr(tmp
), commonbits
);
196 /* Don't need labels; allocate output arrays */
197 out
->nodeLabels
= NULL
;
198 out
->mapTuplesToNodes
= (int *) palloc(sizeof(int) * in
->nTuples
);
199 out
->leafTupleDatums
= (Datum
*) palloc(sizeof(Datum
) * in
->nTuples
);
201 if (differentFamilies
)
203 /* Set up 2-node tuple */
204 out
->hasPrefix
= false;
207 for (i
= 0; i
< in
->nTuples
; i
++)
209 tmp
= DatumGetInetPP(in
->datums
[i
]);
210 out
->mapTuplesToNodes
[i
] =
211 (ip_family(tmp
) == PGSQL_AF_INET
) ? 0 : 1;
212 out
->leafTupleDatums
[i
] = InetPGetDatum(tmp
);
217 /* Set up 4-node tuple */
218 out
->hasPrefix
= true;
220 InetPGetDatum(cidr_set_masklen_internal(prefix
, commonbits
));
223 for (i
= 0; i
< in
->nTuples
; i
++)
225 tmp
= DatumGetInetPP(in
->datums
[i
]);
226 out
->mapTuplesToNodes
[i
] = inet_spg_node_number(tmp
, commonbits
);
227 out
->leafTupleDatums
[i
] = InetPGetDatum(tmp
);
235 * The SP-GiST query consistency check for inner tuples
238 inet_spg_inner_consistent(PG_FUNCTION_ARGS
)
240 spgInnerConsistentIn
*in
= (spgInnerConsistentIn
*) PG_GETARG_POINTER(0);
241 spgInnerConsistentOut
*out
= (spgInnerConsistentOut
*) PG_GETARG_POINTER(1);
247 Assert(!in
->allTheSame
);
248 Assert(in
->nNodes
== 2);
250 /* Identify which child nodes need to be visited */
251 which
= 1 | (1 << 1);
253 for (i
= 0; i
< in
->nkeys
; i
++)
255 StrategyNumber strategy
= in
->scankeys
[i
].sk_strategy
;
256 inet
*argument
= DatumGetInetPP(in
->scankeys
[i
].sk_argument
);
260 case RTLessStrategyNumber
:
261 case RTLessEqualStrategyNumber
:
262 if (ip_family(argument
) == PGSQL_AF_INET
)
266 case RTGreaterEqualStrategyNumber
:
267 case RTGreaterStrategyNumber
:
268 if (ip_family(argument
) == PGSQL_AF_INET6
)
272 case RTNotEqualStrategyNumber
:
276 /* all other ops can only match addrs of same family */
277 if (ip_family(argument
) == PGSQL_AF_INET
)
285 else if (!in
->allTheSame
)
287 Assert(in
->nNodes
== 4);
289 /* Identify which child nodes need to be visited */
290 which
= inet_spg_consistent_bitmap(DatumGetInetPP(in
->prefixDatum
),
291 in
->nkeys
, in
->scankeys
, false);
295 /* Must visit all nodes; we assume there are less than 32 of 'em */
303 out
->nodeNumbers
= (int *) palloc(sizeof(int) * in
->nNodes
);
305 for (i
= 0; i
< in
->nNodes
; i
++)
307 if (which
& (1 << i
))
309 out
->nodeNumbers
[out
->nNodes
] = i
;
319 * The SP-GiST query consistency check for leaf tuples
322 inet_spg_leaf_consistent(PG_FUNCTION_ARGS
)
324 spgLeafConsistentIn
*in
= (spgLeafConsistentIn
*) PG_GETARG_POINTER(0);
325 spgLeafConsistentOut
*out
= (spgLeafConsistentOut
*) PG_GETARG_POINTER(1);
326 inet
*leaf
= DatumGetInetPP(in
->leafDatum
);
328 /* All tests are exact. */
329 out
->recheck
= false;
331 /* Leaf is what it is... */
332 out
->leafValue
= InetPGetDatum(leaf
);
334 /* Use common code to apply the tests. */
335 PG_RETURN_BOOL(inet_spg_consistent_bitmap(leaf
, in
->nkeys
, in
->scankeys
,
340 * Calculate node number (within a 4-node, single-family inner index tuple)
342 * The value must have the same family as the node's prefix, and
343 * commonbits is the mask length of the prefix. We use even or odd
344 * nodes according to the next address bit after the commonbits,
345 * and low or high nodes according to whether the value's mask length
346 * is larger than commonbits.
349 inet_spg_node_number(const inet
*val
, int commonbits
)
353 if (commonbits
< ip_maxbits(val
) &&
354 ip_addr(val
)[commonbits
/ 8] & (1 << (7 - commonbits
% 8)))
356 if (commonbits
< ip_bits(val
))
363 * Calculate bitmap of node numbers that are consistent with the query
365 * This can be used either at a 4-way inner tuple, or at a leaf tuple.
366 * In the latter case, we should return a boolean result (0 or 1)
369 * This definition is pretty odd, but the inner and leaf consistency checks
370 * are mostly common and it seems best to keep them in one function.
373 inet_spg_consistent_bitmap(const inet
*prefix
, int nkeys
, ScanKey scankeys
,
380 /* Initialize result to allow visiting all children */
384 bitmap
= 1 | (1 << 1) | (1 << 2) | (1 << 3);
386 commonbits
= ip_bits(prefix
);
388 for (i
= 0; i
< nkeys
; i
++)
390 inet
*argument
= DatumGetInetPP(scankeys
[i
].sk_argument
);
391 StrategyNumber strategy
= scankeys
[i
].sk_strategy
;
395 * Check 0: different families
397 * Matching families do not help any of the strategies.
399 if (ip_family(argument
) != ip_family(prefix
))
403 case RTLessStrategyNumber
:
404 case RTLessEqualStrategyNumber
:
405 if (ip_family(argument
) < ip_family(prefix
))
409 case RTGreaterEqualStrategyNumber
:
410 case RTGreaterStrategyNumber
:
411 if (ip_family(argument
) > ip_family(prefix
))
415 case RTNotEqualStrategyNumber
:
419 /* For all other cases, we can be sure there is no match */
427 /* Other checks make no sense with different families. */
432 * Check 1: network bit count
434 * Network bit count (ip_bits) helps to check leaves for sub network
435 * and sup network operators. At non-leaf nodes, we know every child
436 * value has greater ip_bits, so we can avoid descending in some cases
439 * This check is less expensive than checking the address bits, so we
440 * are doing this before, but it has to be done after for the basic
441 * comparison strategies, because ip_bits only affect their results
442 * when the common network bits are the same.
446 case RTSubStrategyNumber
:
447 if (commonbits
<= ip_bits(argument
))
448 bitmap
&= (1 << 2) | (1 << 3);
451 case RTSubEqualStrategyNumber
:
452 if (commonbits
< ip_bits(argument
))
453 bitmap
&= (1 << 2) | (1 << 3);
456 case RTSuperStrategyNumber
:
457 if (commonbits
== ip_bits(argument
) - 1)
458 bitmap
&= 1 | (1 << 1);
459 else if (commonbits
>= ip_bits(argument
))
463 case RTSuperEqualStrategyNumber
:
464 if (commonbits
== ip_bits(argument
))
465 bitmap
&= 1 | (1 << 1);
466 else if (commonbits
> ip_bits(argument
))
470 case RTEqualStrategyNumber
:
471 if (commonbits
< ip_bits(argument
))
472 bitmap
&= (1 << 2) | (1 << 3);
473 else if (commonbits
== ip_bits(argument
))
474 bitmap
&= 1 | (1 << 1);
484 * Check 2: common network bits
486 * Compare available common prefix bits to the query, but not beyond
487 * either the query's netmask or the minimum netmask among the
488 * represented values. If these bits don't match the query, we can
489 * eliminate some cases.
491 order
= bitncmp(ip_addr(prefix
), ip_addr(argument
),
492 Min(commonbits
, ip_bits(argument
)));
498 case RTLessStrategyNumber
:
499 case RTLessEqualStrategyNumber
:
504 case RTGreaterEqualStrategyNumber
:
505 case RTGreaterStrategyNumber
:
510 case RTNotEqualStrategyNumber
:
514 /* For all other cases, we can be sure there is no match */
523 * Remaining checks make no sense when common bits don't match.
529 * Check 3: next network bit
531 * We can filter out branch 2 or 3 using the next network bit of the
532 * argument, if it is available.
534 * This check matters for the performance of the search. The results
535 * would be correct without it.
537 if (bitmap
& ((1 << 2) | (1 << 3)) &&
538 commonbits
< ip_bits(argument
))
542 nextbit
= ip_addr(argument
)[commonbits
/ 8] &
543 (1 << (7 - commonbits
% 8));
547 case RTLessStrategyNumber
:
548 case RTLessEqualStrategyNumber
:
550 bitmap
&= 1 | (1 << 1) | (1 << 2);
553 case RTGreaterEqualStrategyNumber
:
554 case RTGreaterStrategyNumber
:
556 bitmap
&= 1 | (1 << 1) | (1 << 3);
559 case RTNotEqualStrategyNumber
:
564 bitmap
&= 1 | (1 << 1) | (1 << 2);
566 bitmap
&= 1 | (1 << 1) | (1 << 3);
575 * Remaining checks are only for the basic comparison strategies. This
576 * test relies on the strategy number ordering defined in stratnum.h.
578 if (strategy
< RTEqualStrategyNumber
||
579 strategy
> RTGreaterEqualStrategyNumber
)
583 * Check 4: network bit count
585 * At this point, we know that the common network bits of the prefix
586 * and the argument are the same, so we can go forward and check the
591 case RTLessStrategyNumber
:
592 case RTLessEqualStrategyNumber
:
593 if (commonbits
== ip_bits(argument
))
594 bitmap
&= 1 | (1 << 1);
595 else if (commonbits
> ip_bits(argument
))
599 case RTGreaterEqualStrategyNumber
:
600 case RTGreaterStrategyNumber
:
601 if (commonbits
< ip_bits(argument
))
602 bitmap
&= (1 << 2) | (1 << 3);
609 /* Remaining checks don't make sense with different ip_bits. */
610 if (commonbits
!= ip_bits(argument
))
614 * Check 5: next host bit
616 * We can filter out branch 0 or 1 using the next host bit of the
617 * argument, if it is available.
619 * This check matters for the performance of the search. The results
620 * would be correct without it. There is no point in running it for
621 * leafs as we have to check the whole address on the next step.
623 if (!leaf
&& bitmap
& (1 | (1 << 1)) &&
624 commonbits
< ip_maxbits(argument
))
628 nextbit
= ip_addr(argument
)[commonbits
/ 8] &
629 (1 << (7 - commonbits
% 8));
633 case RTLessStrategyNumber
:
634 case RTLessEqualStrategyNumber
:
636 bitmap
&= 1 | (1 << 2) | (1 << 3);
639 case RTGreaterEqualStrategyNumber
:
640 case RTGreaterStrategyNumber
:
642 bitmap
&= (1 << 1) | (1 << 2) | (1 << 3);
645 case RTNotEqualStrategyNumber
:
650 bitmap
&= 1 | (1 << 2) | (1 << 3);
652 bitmap
&= (1 << 1) | (1 << 2) | (1 << 3);
661 * Check 6: whole address
663 * This is the last check for correctness of the basic comparison
664 * strategies. It's only appropriate at leaf entries.
668 /* Redo ordering comparison using all address bits */
669 order
= bitncmp(ip_addr(prefix
), ip_addr(argument
),
674 case RTLessStrategyNumber
:
679 case RTLessEqualStrategyNumber
:
684 case RTEqualStrategyNumber
:
689 case RTGreaterEqualStrategyNumber
:
694 case RTGreaterStrategyNumber
:
699 case RTNotEqualStrategyNumber
: