Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * PostgreSQL type definitions for the INET and CIDR types.
3 : : *
4 : : * src/backend/utils/adt/network.c
5 : : *
6 : : * Jon Postel RIP 16 Oct 1998
7 : : */
8 : :
9 : : #include "postgres.h"
10 : :
11 : : #include <sys/socket.h>
12 : : #include <netinet/in.h>
13 : : #include <arpa/inet.h>
14 : :
15 : : #include "access/stratnum.h"
16 : : #include "catalog/pg_opfamily.h"
17 : : #include "catalog/pg_type.h"
18 : : #include "common/hashfn.h"
19 : : #include "common/ip.h"
20 : : #include "lib/hyperloglog.h"
21 : : #include "libpq/libpq-be.h"
22 : : #include "libpq/pqformat.h"
23 : : #include "miscadmin.h"
24 : : #include "nodes/makefuncs.h"
25 : : #include "nodes/nodeFuncs.h"
26 : : #include "nodes/supportnodes.h"
27 : : #include "utils/builtins.h"
28 : : #include "utils/fmgroids.h"
29 : : #include "utils/guc.h"
30 : : #include "utils/inet.h"
31 : : #include "utils/lsyscache.h"
32 : : #include "utils/sortsupport.h"
33 : :
34 : :
35 : : /*
36 : : * An IPv4 netmask size is a value in the range of 0 - 32, which is
37 : : * represented with 6 bits in inet/cidr abbreviated keys where possible.
38 : : *
39 : : * An IPv4 inet/cidr abbreviated key can use up to 25 bits for subnet
40 : : * component.
41 : : */
42 : : #define ABBREV_BITS_INET4_NETMASK_SIZE 6
43 : : #define ABBREV_BITS_INET4_SUBNET 25
44 : :
45 : : /* sortsupport for inet/cidr */
46 : : typedef struct
47 : : {
48 : : int64 input_count; /* number of non-null values seen */
49 : : bool estimating; /* true if estimating cardinality */
50 : :
51 : : hyperLogLogState abbr_card; /* cardinality estimator */
52 : : } network_sortsupport_state;
53 : :
54 : : static int32 network_cmp_internal(inet *a1, inet *a2);
55 : : static int network_fast_cmp(Datum x, Datum y, SortSupport ssup);
56 : : static bool network_abbrev_abort(int memtupcount, SortSupport ssup);
57 : : static Datum network_abbrev_convert(Datum original, SortSupport ssup);
58 : : static List *match_network_function(Node *leftop,
59 : : Node *rightop,
60 : : int indexarg,
61 : : Oid funcid,
62 : : Oid opfamily);
63 : : static List *match_network_subset(Node *leftop,
64 : : Node *rightop,
65 : : bool is_eq,
66 : : Oid opfamily);
67 : : static bool addressOK(unsigned char *a, int bits, int family);
68 : : static inet *internal_inetpl(inet *ip, int64 addend);
69 : :
70 : :
71 : : /*
72 : : * Common INET/CIDR input routine
73 : : */
74 : : static inet *
487 tgl@sss.pgh.pa.us 75 :CBC 2874 : network_in(char *src, bool is_cidr, Node *escontext)
76 : : {
77 : : int bits;
78 : : inet *dst;
79 : :
6218 80 : 2874 : dst = (inet *) palloc0(sizeof(inet));
81 : :
82 : : /*
83 : : * First, check to see if this is an IPv6 or IPv4 address. IPv6 addresses
84 : : * will have a : somewhere in them (several, in fact) so if there is one
85 : : * present, assume it's V6, otherwise assume it's V4.
86 : : */
87 : :
7562 88 [ + + ]: 2874 : if (strchr(src, ':') != NULL)
7600 bruce@momjian.us 89 [ - + ]: 448 : ip_family(dst) = PGSQL_AF_INET6;
90 : : else
91 [ - + ]: 2426 : ip_family(dst) = PGSQL_AF_INET;
92 : :
1701 tgl@sss.pgh.pa.us 93 [ + + - + : 3573 : bits = pg_inet_net_pton(ip_family(dst), src, ip_addr(dst),
- + ]
94 [ - + + + ]: 699 : is_cidr ? ip_addrsize(dst) : -1);
7600 bruce@momjian.us 95 [ + + - + : 2874 : if ((bits < 0) || (bits > ip_maxbits(dst)))
+ + - + ]
487 tgl@sss.pgh.pa.us 96 [ + + + + ]: 15 : ereturn(escontext, NULL,
97 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
98 : : /* translator: first %s is inet or cidr */
99 : : errmsg("invalid input syntax for type %s: \"%s\"",
100 : : is_cidr ? "cidr" : "inet", src)));
101 : :
102 : : /*
103 : : * Error check: CIDR values must not have any bits set beyond the masklen.
104 : : */
6656 bruce@momjian.us 105 [ + + ]: 2859 : if (is_cidr)
106 : : {
7600 107 [ - + - + : 690 : if (!addressOK(ip_addr(dst), bits, ip_family(dst)))
+ + ]
487 tgl@sss.pgh.pa.us 108 [ + + ]: 15 : ereturn(escontext, NULL,
109 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
110 : : errmsg("invalid cidr value: \"%s\"", src),
111 : : errdetail("Value has bits set to right of mask.")));
112 : : }
113 : :
9306 bruce@momjian.us 114 [ - + ]: 2844 : ip_bits(dst) = bits;
6218 tgl@sss.pgh.pa.us 115 [ - + + + ]: 2844 : SET_INET_VARSIZE(dst);
116 : :
9306 bruce@momjian.us 117 : 2844 : return dst;
118 : : }
119 : :
120 : : Datum
8655 tgl@sss.pgh.pa.us 121 : 2175 : inet_in(PG_FUNCTION_ARGS)
122 : : {
123 : 2175 : char *src = PG_GETARG_CSTRING(0);
124 : :
487 125 : 2175 : PG_RETURN_INET_P(network_in(src, false, fcinfo->context));
126 : : }
127 : :
128 : : Datum
8655 129 : 699 : cidr_in(PG_FUNCTION_ARGS)
130 : : {
131 : 699 : char *src = PG_GETARG_CSTRING(0);
132 : :
487 133 : 699 : PG_RETURN_INET_P(network_in(src, true, fcinfo->context));
134 : : }
135 : :
136 : :
137 : : /*
138 : : * Common INET/CIDR output routine
139 : : */
140 : : static char *
6653 141 : 7038 : network_out(inet *src, bool is_cidr)
142 : : {
143 : : char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
144 : : char *dst;
145 : : int len;
146 : :
1701 147 [ + + + + : 7038 : dst = pg_inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src),
+ + ]
148 : : tmp, sizeof(tmp));
7600 bruce@momjian.us 149 [ - + ]: 7038 : if (dst == NULL)
7567 tgl@sss.pgh.pa.us 150 [ # # ]:UBC 0 : ereport(ERROR,
151 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
152 : : errmsg("could not format inet value: %m")));
153 : :
154 : : /* For CIDR, add /n if not present */
6653 tgl@sss.pgh.pa.us 155 [ + + + + ]:CBC 7038 : if (is_cidr && strchr(tmp, '/') == NULL)
156 : : {
7600 bruce@momjian.us 157 : 539 : len = strlen(tmp);
158 [ + + ]: 539 : snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src));
159 : : }
160 : :
6653 tgl@sss.pgh.pa.us 161 : 7038 : return pstrdup(tmp);
162 : : }
163 : :
164 : : Datum
165 : 4238 : inet_out(PG_FUNCTION_ARGS)
166 : : {
4507 heikki.linnakangas@i 167 : 4238 : inet *src = PG_GETARG_INET_PP(0);
168 : :
6653 tgl@sss.pgh.pa.us 169 : 4238 : PG_RETURN_CSTRING(network_out(src, false));
170 : : }
171 : :
172 : : Datum
8655 173 : 2800 : cidr_out(PG_FUNCTION_ARGS)
174 : : {
4507 heikki.linnakangas@i 175 : 2800 : inet *src = PG_GETARG_INET_PP(0);
176 : :
6653 tgl@sss.pgh.pa.us 177 : 2800 : PG_RETURN_CSTRING(network_out(src, true));
178 : : }
179 : :
180 : :
181 : : /*
182 : : * network_recv - converts external binary format to inet
183 : : *
184 : : * The external representation is (one byte apiece for)
185 : : * family, bits, is_cidr, address length, address in network byte order.
186 : : *
187 : : * Presence of is_cidr is largely for historical reasons, though it might
188 : : * allow some code-sharing on the client side. We send it correctly on
189 : : * output, but ignore the value on input.
190 : : */
191 : : static inet *
6653 tgl@sss.pgh.pa.us 192 :UBC 0 : network_recv(StringInfo buf, bool is_cidr)
193 : : {
194 : : inet *addr;
195 : : char *addrptr;
196 : : int bits;
197 : : int nb,
198 : : i;
199 : :
200 : : /* make sure any unused bits in a CIDR value are zeroed */
6218 201 : 0 : addr = (inet *) palloc0(sizeof(inet));
202 : :
7642 203 [ # # ]: 0 : ip_family(addr) = pq_getmsgbyte(buf);
7562 204 [ # # # # ]: 0 : if (ip_family(addr) != PGSQL_AF_INET &&
205 [ # # # # ]: 0 : ip_family(addr) != PGSQL_AF_INET6)
7567 206 [ # # # # ]: 0 : ereport(ERROR,
207 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
208 : : /* translator: %s is inet or cidr */
209 : : errmsg("invalid address family in external \"%s\" value",
210 : : is_cidr ? "cidr" : "inet")));
7642 211 : 0 : bits = pq_getmsgbyte(buf);
7600 bruce@momjian.us 212 [ # # # # : 0 : if (bits < 0 || bits > ip_maxbits(addr))
# # # # ]
7567 tgl@sss.pgh.pa.us 213 [ # # # # ]: 0 : ereport(ERROR,
214 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
215 : : /* translator: %s is inet or cidr */
216 : : errmsg("invalid bits in external \"%s\" value",
217 : : is_cidr ? "cidr" : "inet")));
7642 218 [ # # ]: 0 : ip_bits(addr) = bits;
6653 219 : 0 : i = pq_getmsgbyte(buf); /* ignore is_cidr */
7642 220 : 0 : nb = pq_getmsgbyte(buf);
221 [ # # # # : 0 : if (nb != ip_addrsize(addr))
# # ]
7567 222 [ # # # # ]: 0 : ereport(ERROR,
223 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
224 : : /* translator: %s is inet or cidr */
225 : : errmsg("invalid length in external \"%s\" value",
226 : : is_cidr ? "cidr" : "inet")));
227 : :
7559 bruce@momjian.us 228 [ # # ]: 0 : addrptr = (char *) ip_addr(addr);
7642 tgl@sss.pgh.pa.us 229 [ # # ]: 0 : for (i = 0; i < nb; i++)
230 : 0 : addrptr[i] = pq_getmsgbyte(buf);
231 : :
232 : : /*
233 : : * Error check: CIDR values must not have any bits set beyond the masklen.
234 : : */
6653 235 [ # # ]: 0 : if (is_cidr)
236 : : {
7600 bruce@momjian.us 237 [ # # # # : 0 : if (!addressOK(ip_addr(addr), bits, ip_family(addr)))
# # ]
7567 tgl@sss.pgh.pa.us 238 [ # # ]: 0 : ereport(ERROR,
239 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
240 : : errmsg("invalid external \"cidr\" value"),
241 : : errdetail("Value has bits set to right of mask.")));
242 : : }
243 : :
6218 244 [ # # # # ]: 0 : SET_INET_VARSIZE(addr);
245 : :
6653 246 : 0 : return addr;
247 : : }
248 : :
249 : : Datum
250 : 0 : inet_recv(PG_FUNCTION_ARGS)
251 : : {
252 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
253 : :
254 : 0 : PG_RETURN_INET_P(network_recv(buf, false));
255 : : }
256 : :
257 : : Datum
7642 258 : 0 : cidr_recv(PG_FUNCTION_ARGS)
259 : : {
6653 260 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
261 : :
262 : 0 : PG_RETURN_INET_P(network_recv(buf, true));
263 : : }
264 : :
265 : :
266 : : /*
267 : : * network_send - converts inet to binary format
268 : : */
269 : : static bytea *
270 : 0 : network_send(inet *addr, bool is_cidr)
271 : : {
272 : : StringInfoData buf;
273 : : char *addrptr;
274 : : int nb,
275 : : i;
276 : :
7642 277 : 0 : pq_begintypsend(&buf);
278 [ # # ]: 0 : pq_sendbyte(&buf, ip_family(addr));
279 [ # # ]: 0 : pq_sendbyte(&buf, ip_bits(addr));
6653 280 : 0 : pq_sendbyte(&buf, is_cidr);
7642 281 [ # # # # ]: 0 : nb = ip_addrsize(addr);
282 [ # # ]: 0 : if (nb < 0)
283 : 0 : nb = 0;
284 : 0 : pq_sendbyte(&buf, nb);
7559 bruce@momjian.us 285 [ # # ]: 0 : addrptr = (char *) ip_addr(addr);
7642 tgl@sss.pgh.pa.us 286 [ # # ]: 0 : for (i = 0; i < nb; i++)
287 : 0 : pq_sendbyte(&buf, addrptr[i]);
6653 288 : 0 : return pq_endtypsend(&buf);
289 : : }
290 : :
291 : : Datum
292 : 0 : inet_send(PG_FUNCTION_ARGS)
293 : : {
4507 heikki.linnakangas@i 294 : 0 : inet *addr = PG_GETARG_INET_PP(0);
295 : :
6653 tgl@sss.pgh.pa.us 296 : 0 : PG_RETURN_BYTEA_P(network_send(addr, false));
297 : : }
298 : :
299 : : Datum
7642 300 : 0 : cidr_send(PG_FUNCTION_ARGS)
301 : : {
4507 heikki.linnakangas@i 302 : 0 : inet *addr = PG_GETARG_INET_PP(0);
303 : :
6653 tgl@sss.pgh.pa.us 304 : 0 : PG_RETURN_BYTEA_P(network_send(addr, true));
305 : : }
306 : :
307 : :
308 : : Datum
6653 tgl@sss.pgh.pa.us 309 :CBC 1770 : inet_to_cidr(PG_FUNCTION_ARGS)
310 : : {
4507 heikki.linnakangas@i 311 : 1770 : inet *src = PG_GETARG_INET_PP(0);
312 : : int bits;
313 : :
6653 tgl@sss.pgh.pa.us 314 [ + + ]: 1770 : bits = ip_bits(src);
315 : :
316 : : /* safety check */
317 [ + - + + : 1770 : if ((bits < 0) || (bits > ip_maxbits(src)))
+ + - + ]
6653 tgl@sss.pgh.pa.us 318 [ # # ]:UBC 0 : elog(ERROR, "invalid inet bit length: %d", bits);
319 : :
2791 tgl@sss.pgh.pa.us 320 :CBC 1770 : PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits));
321 : : }
322 : :
323 : : Datum
8341 bruce@momjian.us 324 : 75 : inet_set_masklen(PG_FUNCTION_ARGS)
325 : : {
4507 heikki.linnakangas@i 326 : 75 : inet *src = PG_GETARG_INET_PP(0);
8207 bruce@momjian.us 327 : 75 : int bits = PG_GETARG_INT32(1);
328 : : inet *dst;
329 : :
7559 330 [ + + ]: 75 : if (bits == -1)
331 [ - + + - ]: 24 : bits = ip_maxbits(src);
332 : :
7600 333 [ + - - + : 75 : if ((bits < 0) || (bits > ip_maxbits(src)))
+ + - + ]
7567 tgl@sss.pgh.pa.us 334 [ # # ]:UBC 0 : ereport(ERROR,
335 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
336 : : errmsg("invalid mask length: %d", bits)));
337 : :
338 : : /* clone the original data */
6218 tgl@sss.pgh.pa.us 339 [ - + - - :CBC 75 : dst = (inet *) palloc(VARSIZE_ANY(src));
- - - - -
+ ]
340 [ - + - - : 75 : memcpy(dst, src, VARSIZE_ANY(src));
- - - - -
+ ]
341 : :
8207 bruce@momjian.us 342 [ - + ]: 75 : ip_bits(dst) = bits;
343 : :
8341 344 : 75 : PG_RETURN_INET_P(dst);
345 : : }
346 : :
347 : : Datum
6653 tgl@sss.pgh.pa.us 348 :UBC 0 : cidr_set_masklen(PG_FUNCTION_ARGS)
349 : : {
4507 heikki.linnakangas@i 350 : 0 : inet *src = PG_GETARG_INET_PP(0);
6653 tgl@sss.pgh.pa.us 351 : 0 : int bits = PG_GETARG_INT32(1);
352 : :
353 [ # # ]: 0 : if (bits == -1)
354 [ # # # # ]: 0 : bits = ip_maxbits(src);
355 : :
356 [ # # # # : 0 : if ((bits < 0) || (bits > ip_maxbits(src)))
# # # # ]
357 [ # # ]: 0 : ereport(ERROR,
358 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
359 : : errmsg("invalid mask length: %d", bits)));
360 : :
2791 361 : 0 : PG_RETURN_INET_P(cidr_set_masklen_internal(src, bits));
362 : : }
363 : :
364 : : /*
365 : : * Copy src and set mask length to 'bits' (which must be valid for the family)
366 : : */
367 : : inet *
2791 tgl@sss.pgh.pa.us 368 :CBC 1884 : cidr_set_masklen_internal(const inet *src, int bits)
369 : : {
370 : 1884 : inet *dst = (inet *) palloc0(sizeof(inet));
371 : :
372 [ + + - + ]: 1884 : ip_family(dst) = ip_family(src);
373 [ - + ]: 1884 : ip_bits(dst) = bits;
374 : :
375 [ + - ]: 1884 : if (bits > 0)
376 : : {
377 [ - + + + : 1884 : Assert(bits <= ip_maxbits(dst));
- + ]
378 : :
379 : : /* Clone appropriate bytes of the address, leaving the rest 0 */
380 [ + + - + ]: 1884 : memcpy(ip_addr(dst), ip_addr(src), (bits + 7) / 8);
381 : :
382 : : /* Clear any unwanted bits in the last partial byte */
383 [ + + ]: 1884 : if (bits % 8)
384 [ - + - + ]: 30 : ip_addr(dst)[bits / 8] &= ~(0xFF >> (bits % 8));
385 : : }
386 : :
387 : : /* Set varlena header correctly */
388 [ - + + + ]: 1884 : SET_INET_VARSIZE(dst);
389 : :
390 : 1884 : return dst;
391 : : }
392 : :
393 : : /*
394 : : * Basic comparison function for sorting and inet/cidr comparisons.
395 : : *
396 : : * Comparison is first on the common bits of the network part, then on
397 : : * the length of the network part, and then on the whole unmasked address.
398 : : * The effect is that the network part is the major sort key, and for
399 : : * equal network parts we sort on the host part. Note this is only sane
400 : : * for CIDR if address bits to the right of the mask are guaranteed zero;
401 : : * otherwise logically-equal CIDRs might compare different.
402 : : */
403 : :
404 : : static int32
8655 405 : 250519 : network_cmp_internal(inet *a1, inet *a2)
406 : : {
7600 bruce@momjian.us 407 [ + + + + : 250519 : if (ip_family(a1) == ip_family(a2))
+ + ]
408 : : {
409 : : int order;
410 : :
411 [ + + ]: 173737 : order = bitncmp(ip_addr(a1), ip_addr(a2),
7559 412 [ + + + + : 173737 : Min(ip_bits(a1), ip_bits(a2)));
+ + ]
8570 tgl@sss.pgh.pa.us 413 [ + + ]: 173737 : if (order != 0)
414 : 161823 : return order;
415 [ + + + + ]: 11914 : order = ((int) ip_bits(a1)) - ((int) ip_bits(a2));
8655 416 [ + + ]: 11914 : if (order != 0)
417 : 540 : return order;
7600 bruce@momjian.us 418 [ + + + + : 11374 : return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1));
+ + + + ]
419 : : }
420 : :
421 [ + + + + ]: 76782 : return ip_family(a1) - ip_family(a2);
422 : : }
423 : :
424 : : Datum
8655 tgl@sss.pgh.pa.us 425 : 134 : network_cmp(PG_FUNCTION_ARGS)
426 : : {
4507 heikki.linnakangas@i 427 : 134 : inet *a1 = PG_GETARG_INET_PP(0);
428 : 134 : inet *a2 = PG_GETARG_INET_PP(1);
429 : :
8655 tgl@sss.pgh.pa.us 430 : 134 : PG_RETURN_INT32(network_cmp_internal(a1, a2));
431 : : }
432 : :
433 : : /*
434 : : * SortSupport strategy routine
435 : : */
436 : : Datum
1718 pg@bowt.ie 437 : 165 : network_sortsupport(PG_FUNCTION_ARGS)
438 : : {
439 : 165 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
440 : :
441 : 165 : ssup->comparator = network_fast_cmp;
442 : 165 : ssup->ssup_extra = NULL;
443 : :
444 [ + + ]: 165 : if (ssup->abbreviate)
445 : : {
446 : : network_sortsupport_state *uss;
447 : : MemoryContext oldcontext;
448 : :
449 : 80 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
450 : :
451 : 80 : uss = palloc(sizeof(network_sortsupport_state));
452 : 80 : uss->input_count = 0;
453 : 80 : uss->estimating = true;
454 : 80 : initHyperLogLog(&uss->abbr_card, 10);
455 : :
456 : 80 : ssup->ssup_extra = uss;
457 : :
743 john.naylor@postgres 458 : 80 : ssup->comparator = ssup_datum_unsigned_cmp;
1718 pg@bowt.ie 459 : 80 : ssup->abbrev_converter = network_abbrev_convert;
460 : 80 : ssup->abbrev_abort = network_abbrev_abort;
461 : 80 : ssup->abbrev_full_comparator = network_fast_cmp;
462 : :
463 : 80 : MemoryContextSwitchTo(oldcontext);
464 : : }
465 : :
466 : 165 : PG_RETURN_VOID();
467 : : }
468 : :
469 : : /*
470 : : * SortSupport comparison func
471 : : */
472 : : static int
473 : 17297 : network_fast_cmp(Datum x, Datum y, SortSupport ssup)
474 : : {
475 : 17297 : inet *arg1 = DatumGetInetPP(x);
476 : 17297 : inet *arg2 = DatumGetInetPP(y);
477 : :
478 : 17297 : return network_cmp_internal(arg1, arg2);
479 : : }
480 : :
481 : : /*
482 : : * Callback for estimating effectiveness of abbreviated key optimization.
483 : : *
484 : : * We pay no attention to the cardinality of the non-abbreviated data, because
485 : : * there is no equality fast-path within authoritative inet comparator.
486 : : */
487 : : static bool
488 : 21 : network_abbrev_abort(int memtupcount, SortSupport ssup)
489 : : {
490 : 21 : network_sortsupport_state *uss = ssup->ssup_extra;
491 : : double abbr_card;
492 : :
493 [ - + - - : 21 : if (memtupcount < 10000 || uss->input_count < 10000 || !uss->estimating)
- - ]
494 : 21 : return false;
495 : :
1718 pg@bowt.ie 496 :UBC 0 : abbr_card = estimateHyperLogLog(&uss->abbr_card);
497 : :
498 : : /*
499 : : * If we have >100k distinct values, then even if we were sorting many
500 : : * billion rows we'd likely still break even, and the penalty of undoing
501 : : * that many rows of abbrevs would probably not be worth it. At this point
502 : : * we stop counting because we know that we're now fully committed.
503 : : */
504 [ # # ]: 0 : if (abbr_card > 100000.0)
505 : : {
506 : : #ifdef TRACE_SORT
507 [ # # ]: 0 : if (trace_sort)
508 [ # # ]: 0 : elog(LOG,
509 : : "network_abbrev: estimation ends at cardinality %f"
510 : : " after " INT64_FORMAT " values (%d rows)",
511 : : abbr_card, uss->input_count, memtupcount);
512 : : #endif
513 : 0 : uss->estimating = false;
514 : 0 : return false;
515 : : }
516 : :
517 : : /*
518 : : * Target minimum cardinality is 1 per ~2k of non-null inputs. 0.5 row
519 : : * fudge factor allows us to abort earlier on genuinely pathological data
520 : : * where we've had exactly one abbreviated value in the first 2k
521 : : * (non-null) rows.
522 : : */
523 [ # # ]: 0 : if (abbr_card < uss->input_count / 2000.0 + 0.5)
524 : : {
525 : : #ifdef TRACE_SORT
526 [ # # ]: 0 : if (trace_sort)
527 [ # # ]: 0 : elog(LOG,
528 : : "network_abbrev: aborting abbreviation at cardinality %f"
529 : : " below threshold %f after " INT64_FORMAT " values (%d rows)",
530 : : abbr_card, uss->input_count / 2000.0 + 0.5, uss->input_count,
531 : : memtupcount);
532 : : #endif
533 : 0 : return true;
534 : : }
535 : :
536 : : #ifdef TRACE_SORT
537 [ # # ]: 0 : if (trace_sort)
538 [ # # ]: 0 : elog(LOG,
539 : : "network_abbrev: cardinality %f after " INT64_FORMAT
540 : : " values (%d rows)", abbr_card, uss->input_count, memtupcount);
541 : : #endif
542 : :
543 : 0 : return false;
544 : : }
545 : :
546 : : /*
547 : : * SortSupport conversion routine. Converts original inet/cidr representation
548 : : * to abbreviated key representation that works with simple 3-way unsigned int
549 : : * comparisons. The network_cmp_internal() rules for sorting inet/cidr datums
550 : : * are followed by abbreviated comparisons by an encoding scheme that
551 : : * conditions keys through careful use of padding.
552 : : *
553 : : * Some background: inet values have three major components (take for example
554 : : * the address 1.2.3.4/24):
555 : : *
556 : : * * A network, or netmasked bits (1.2.3.0).
557 : : * * A netmask size (/24).
558 : : * * A subnet, or bits outside of the netmask (0.0.0.4).
559 : : *
560 : : * cidr values are the same except that with only the first two components --
561 : : * all their subnet bits *must* be zero (1.2.3.0/24).
562 : : *
563 : : * IPv4 and IPv6 are identical in this makeup, with the difference being that
564 : : * IPv4 addresses have a maximum of 32 bits compared to IPv6's 64 bits, so in
565 : : * IPv6 each part may be larger.
566 : : *
567 : : * inet/cidr types compare using these sorting rules. If inequality is detected
568 : : * at any step, comparison is finished. If any rule is a tie, the algorithm
569 : : * drops through to the next to break it:
570 : : *
571 : : * 1. IPv4 always appears before IPv6.
572 : : * 2. Network bits are compared.
573 : : * 3. Netmask size is compared.
574 : : * 4. All bits are compared (having made it here, we know that both
575 : : * netmasked bits and netmask size are equal, so we're in effect only
576 : : * comparing subnet bits).
577 : : *
578 : : * When generating abbreviated keys for SortSupport, we pack as much as we can
579 : : * into a datum while ensuring that when comparing those keys as integers,
580 : : * these rules will be respected. Exact contents depend on IP family and datum
581 : : * size.
582 : : *
583 : : * IPv4
584 : : * ----
585 : : *
586 : : * 4 byte datums:
587 : : *
588 : : * Start with 1 bit for the IP family (IPv4 or IPv6; this bit is present in
589 : : * every case below) followed by all but 1 of the netmasked bits.
590 : : *
591 : : * +----------+---------------------+
592 : : * | 1 bit IP | 31 bits network | (1 bit network
593 : : * | family | (truncated) | omitted)
594 : : * +----------+---------------------+
595 : : *
596 : : * 8 byte datums:
597 : : *
598 : : * We have space to store all netmasked bits, followed by the netmask size,
599 : : * followed by 25 bits of the subnet (25 bits is usually more than enough in
600 : : * practice). cidr datums always have all-zero subnet bits.
601 : : *
602 : : * +----------+-----------------------+--------------+--------------------+
603 : : * | 1 bit IP | 32 bits network | 6 bits | 25 bits subnet |
604 : : * | family | (full) | network size | (truncated) |
605 : : * +----------+-----------------------+--------------+--------------------+
606 : : *
607 : : * IPv6
608 : : * ----
609 : : *
610 : : * 4 byte datums:
611 : : *
612 : : * +----------+---------------------+
613 : : * | 1 bit IP | 31 bits network | (up to 97 bits
614 : : * | family | (truncated) | network omitted)
615 : : * +----------+---------------------+
616 : : *
617 : : * 8 byte datums:
618 : : *
619 : : * +----------+---------------------------------+
620 : : * | 1 bit IP | 63 bits network | (up to 65 bits
621 : : * | family | (truncated) | network omitted)
622 : : * +----------+---------------------------------+
623 : : */
624 : : static Datum
1718 pg@bowt.ie 625 :CBC 774 : network_abbrev_convert(Datum original, SortSupport ssup)
626 : : {
627 : 774 : network_sortsupport_state *uss = ssup->ssup_extra;
628 : 774 : inet *authoritative = DatumGetInetPP(original);
629 : : Datum res,
630 : : ipaddr_datum,
631 : : subnet_bitmask,
632 : : network;
633 : : int subnet_size;
634 : :
635 [ + + + + : 774 : Assert(ip_family(authoritative) == PGSQL_AF_INET ||
+ + - + ]
636 : : ip_family(authoritative) == PGSQL_AF_INET6);
637 : :
638 : : /*
639 : : * Get an unsigned integer representation of the IP address by taking its
640 : : * first 4 or 8 bytes. Always take all 4 bytes of an IPv4 address. Take
641 : : * the first 8 bytes of an IPv6 address with an 8 byte datum and 4 bytes
642 : : * otherwise.
643 : : *
644 : : * We're consuming an array of unsigned char, so byteswap on little endian
645 : : * systems (an inet's ipaddr field stores the most significant byte
646 : : * first).
647 : : */
648 [ + + + + ]: 774 : if (ip_family(authoritative) == PGSQL_AF_INET)
649 : : {
650 : : uint32 ipaddr_datum32;
651 : :
652 [ + + ]: 585 : memcpy(&ipaddr_datum32, ip_addr(authoritative), sizeof(uint32));
653 : :
654 : : /* Must byteswap on little-endian machines */
655 : : #ifndef WORDS_BIGENDIAN
656 : 585 : ipaddr_datum = pg_bswap32(ipaddr_datum32);
657 : : #else
658 : : ipaddr_datum = ipaddr_datum32;
659 : : #endif
660 : :
661 : : /* Initialize result without setting ipfamily bit */
662 : 585 : res = (Datum) 0;
663 : : }
664 : : else
665 : : {
666 [ + + ]: 189 : memcpy(&ipaddr_datum, ip_addr(authoritative), sizeof(Datum));
667 : :
668 : : /* Must byteswap on little-endian machines */
669 : 189 : ipaddr_datum = DatumBigEndianToNative(ipaddr_datum);
670 : :
671 : : /* Initialize result with ipfamily (most significant) bit set */
672 : 189 : res = ((Datum) 1) << (SIZEOF_DATUM * BITS_PER_BYTE - 1);
673 : : }
674 : :
675 : : /*
676 : : * ipaddr_datum must be "split": high order bits go in "network" component
677 : : * of abbreviated key (often with zeroed bits at the end due to masking),
678 : : * while low order bits go in "subnet" component when there is space for
679 : : * one. This is often accomplished by generating a temp datum subnet
680 : : * bitmask, which we may reuse later when generating the subnet bits
681 : : * themselves. (Note that subnet bits are only used with IPv4 datums on
682 : : * platforms where datum is 8 bytes.)
683 : : *
684 : : * The number of bits in subnet is used to generate a datum subnet
685 : : * bitmask. For example, with a /24 IPv4 datum there are 8 subnet bits
686 : : * (since 32 - 24 is 8), so the final subnet bitmask is B'1111 1111'. We
687 : : * need explicit handling for cases where the ipaddr bits cannot all fit
688 : : * in a datum, though (otherwise we'd incorrectly mask the network
689 : : * component with IPv6 values).
690 : : */
691 [ + + + + : 774 : subnet_size = ip_maxbits(authoritative) - ip_bits(authoritative);
+ + ]
692 [ - + ]: 774 : Assert(subnet_size >= 0);
693 : : /* subnet size must work with prefix ipaddr cases */
694 : 774 : subnet_size %= SIZEOF_DATUM * BITS_PER_BYTE;
695 [ + + + + ]: 774 : if (ip_bits(authoritative) == 0)
696 : : {
697 : : /* Fit as many ipaddr bits as possible into subnet */
698 : 84 : subnet_bitmask = ((Datum) 0) - 1;
699 : 84 : network = 0;
700 : : }
701 [ + + + + ]: 690 : else if (ip_bits(authoritative) < SIZEOF_DATUM * BITS_PER_BYTE)
702 : : {
703 : : /* Split ipaddr bits between network and subnet */
704 : 585 : subnet_bitmask = (((Datum) 1) << subnet_size) - 1;
705 : 585 : network = ipaddr_datum & ~subnet_bitmask;
706 : : }
707 : : else
708 : : {
709 : : /* Fit as many ipaddr bits as possible into network */
710 : 105 : subnet_bitmask = 0;
711 : 105 : network = ipaddr_datum;
712 : : }
713 : :
714 : : #if SIZEOF_DATUM == 8
715 [ + + + + ]: 774 : if (ip_family(authoritative) == PGSQL_AF_INET)
716 : : {
717 : : /*
718 : : * IPv4 with 8 byte datums: keep all 32 netmasked bits, netmask size,
719 : : * and most significant 25 subnet bits
720 : : */
721 [ + + ]: 585 : Datum netmask_size = (Datum) ip_bits(authoritative);
722 : : Datum subnet;
723 : :
724 : : /*
725 : : * Shift left 31 bits: 6 bits netmask size + 25 subnet bits.
726 : : *
727 : : * We don't make any distinction between network bits that are zero
728 : : * due to masking and "true"/non-masked zero bits. An abbreviated
729 : : * comparison that is resolved by comparing a non-masked and non-zero
730 : : * bit to a masked/zeroed bit is effectively resolved based on
731 : : * ip_bits(), even though the comparison won't reach the netmask_size
732 : : * bits.
733 : : */
734 : 585 : network <<= (ABBREV_BITS_INET4_NETMASK_SIZE +
735 : : ABBREV_BITS_INET4_SUBNET);
736 : :
737 : : /* Shift size to make room for subnet bits at the end */
738 : 585 : netmask_size <<= ABBREV_BITS_INET4_SUBNET;
739 : :
740 : : /* Extract subnet bits without shifting them */
741 : 585 : subnet = ipaddr_datum & subnet_bitmask;
742 : :
743 : : /*
744 : : * If we have more than 25 subnet bits, we can't fit everything. Shift
745 : : * subnet down to avoid clobbering bits that are only supposed to be
746 : : * used for netmask_size.
747 : : *
748 : : * Discarding the least significant subnet bits like this is correct
749 : : * because abbreviated comparisons that are resolved at the subnet
750 : : * level must have had equal netmask_size/ip_bits() values in order to
751 : : * get that far.
752 : : */
753 [ + + ]: 585 : if (subnet_size > ABBREV_BITS_INET4_SUBNET)
754 : 72 : subnet >>= subnet_size - ABBREV_BITS_INET4_SUBNET;
755 : :
756 : : /*
757 : : * Assemble the final abbreviated key without clobbering the ipfamily
758 : : * bit that must remain a zero.
759 : : */
760 : 585 : res |= network | netmask_size | subnet;
761 : : }
762 : : else
763 : : #endif
764 : : {
765 : : /*
766 : : * 4 byte datums, or IPv6 with 8 byte datums: Use as many of the
767 : : * netmasked bits as will fit in final abbreviated key. Avoid
768 : : * clobbering the ipfamily bit that was set earlier.
769 : : */
770 : 189 : res |= network >> 1;
771 : : }
772 : :
773 : 774 : uss->input_count += 1;
774 : :
775 : : /* Hash abbreviated key */
776 [ + - ]: 774 : if (uss->estimating)
777 : : {
778 : : uint32 tmp;
779 : :
780 : : #if SIZEOF_DATUM == 8
781 : 774 : tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
782 : : #else /* SIZEOF_DATUM != 8 */
783 : : tmp = (uint32) res;
784 : : #endif
785 : :
786 : 774 : addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
787 : : }
788 : :
789 : 774 : return res;
790 : : }
791 : :
792 : : /*
793 : : * Boolean ordering tests.
794 : : */
795 : : Datum
8655 tgl@sss.pgh.pa.us 796 : 151643 : network_lt(PG_FUNCTION_ARGS)
797 : : {
4507 heikki.linnakangas@i 798 : 151643 : inet *a1 = PG_GETARG_INET_PP(0);
799 : 151643 : inet *a2 = PG_GETARG_INET_PP(1);
800 : :
8655 tgl@sss.pgh.pa.us 801 : 151643 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0);
802 : : }
803 : :
804 : : Datum
805 : 9496 : network_le(PG_FUNCTION_ARGS)
806 : : {
4507 heikki.linnakangas@i 807 : 9496 : inet *a1 = PG_GETARG_INET_PP(0);
808 : 9496 : inet *a2 = PG_GETARG_INET_PP(1);
809 : :
8655 tgl@sss.pgh.pa.us 810 : 9496 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0);
811 : : }
812 : :
813 : : Datum
814 : 51084 : network_eq(PG_FUNCTION_ARGS)
815 : : {
4507 heikki.linnakangas@i 816 : 51084 : inet *a1 = PG_GETARG_INET_PP(0);
817 : 51084 : inet *a2 = PG_GETARG_INET_PP(1);
818 : :
8655 tgl@sss.pgh.pa.us 819 : 51084 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0);
820 : : }
821 : :
822 : : Datum
823 : 9586 : network_ge(PG_FUNCTION_ARGS)
824 : : {
4507 heikki.linnakangas@i 825 : 9586 : inet *a1 = PG_GETARG_INET_PP(0);
826 : 9586 : inet *a2 = PG_GETARG_INET_PP(1);
827 : :
8655 tgl@sss.pgh.pa.us 828 : 9586 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0);
829 : : }
830 : :
831 : : Datum
832 : 11036 : network_gt(PG_FUNCTION_ARGS)
833 : : {
4507 heikki.linnakangas@i 834 : 11036 : inet *a1 = PG_GETARG_INET_PP(0);
835 : 11036 : inet *a2 = PG_GETARG_INET_PP(1);
836 : :
8655 tgl@sss.pgh.pa.us 837 : 11036 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0);
838 : : }
839 : :
840 : : Datum
841 : 51 : network_ne(PG_FUNCTION_ARGS)
842 : : {
4507 heikki.linnakangas@i 843 : 51 : inet *a1 = PG_GETARG_INET_PP(0);
844 : 51 : inet *a2 = PG_GETARG_INET_PP(1);
845 : :
8655 tgl@sss.pgh.pa.us 846 : 51 : PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0);
847 : : }
848 : :
849 : : /*
850 : : * MIN/MAX support functions.
851 : : */
852 : : Datum
3517 853 : 96 : network_smaller(PG_FUNCTION_ARGS)
854 : : {
855 : 96 : inet *a1 = PG_GETARG_INET_PP(0);
856 : 96 : inet *a2 = PG_GETARG_INET_PP(1);
857 : :
858 [ + + ]: 96 : if (network_cmp_internal(a1, a2) < 0)
859 : 57 : PG_RETURN_INET_P(a1);
860 : : else
861 : 39 : PG_RETURN_INET_P(a2);
862 : : }
863 : :
864 : : Datum
865 : 96 : network_larger(PG_FUNCTION_ARGS)
866 : : {
867 : 96 : inet *a1 = PG_GETARG_INET_PP(0);
868 : 96 : inet *a2 = PG_GETARG_INET_PP(1);
869 : :
870 [ + + ]: 96 : if (network_cmp_internal(a1, a2) > 0)
871 : 78 : PG_RETURN_INET_P(a1);
872 : : else
873 : 18 : PG_RETURN_INET_P(a2);
874 : : }
875 : :
876 : : /*
877 : : * Support function for hash indexes on inet/cidr.
878 : : */
879 : : Datum
7245 880 : 3048 : hashinet(PG_FUNCTION_ARGS)
881 : : {
4507 heikki.linnakangas@i 882 : 3048 : inet *addr = PG_GETARG_INET_PP(0);
7245 tgl@sss.pgh.pa.us 883 [ + + + + ]: 3048 : int addrsize = ip_addrsize(addr);
884 : :
885 : : /* XXX this assumes there are no pad bytes in the data structure */
6218 886 [ + + ]: 3048 : return hash_any((unsigned char *) VARDATA_ANY(addr), addrsize + 2);
887 : : }
888 : :
889 : : Datum
2418 rhaas@postgresql.org 890 : 30 : hashinetextended(PG_FUNCTION_ARGS)
891 : : {
892 : 30 : inet *addr = PG_GETARG_INET_PP(0);
893 [ - + + - ]: 30 : int addrsize = ip_addrsize(addr);
894 : :
895 [ - + ]: 30 : return hash_any_extended((unsigned char *) VARDATA_ANY(addr), addrsize + 2,
896 : 30 : PG_GETARG_INT64(1));
897 : : }
898 : :
899 : : /*
900 : : * Boolean network-inclusion tests.
901 : : */
902 : : Datum
8655 tgl@sss.pgh.pa.us 903 : 3066 : network_sub(PG_FUNCTION_ARGS)
904 : : {
4507 heikki.linnakangas@i 905 : 3066 : inet *a1 = PG_GETARG_INET_PP(0);
906 : 3066 : inet *a2 = PG_GETARG_INET_PP(1);
907 : :
7600 bruce@momjian.us 908 [ + - + + : 3066 : if (ip_family(a1) == ip_family(a2))
+ + ]
909 : : {
3753 tgl@sss.pgh.pa.us 910 [ + - + + : 2466 : PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2) &&
+ + + + +
+ + - +
+ ]
911 : : bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
912 : : }
913 : :
7600 bruce@momjian.us 914 : 600 : PG_RETURN_BOOL(false);
915 : : }
916 : :
917 : : Datum
8655 tgl@sss.pgh.pa.us 918 : 4953 : network_subeq(PG_FUNCTION_ARGS)
919 : : {
4507 heikki.linnakangas@i 920 : 4953 : inet *a1 = PG_GETARG_INET_PP(0);
921 : 4953 : inet *a2 = PG_GETARG_INET_PP(1);
922 : :
7600 bruce@momjian.us 923 [ + - + + : 4953 : if (ip_family(a1) == ip_family(a2))
+ + ]
924 : : {
3753 tgl@sss.pgh.pa.us 925 [ + - + + : 3069 : PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2) &&
+ + + + +
+ + - +
+ ]
926 : : bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
927 : : }
928 : :
7600 bruce@momjian.us 929 : 1884 : PG_RETURN_BOOL(false);
930 : : }
931 : :
932 : : Datum
8655 tgl@sss.pgh.pa.us 933 : 3090 : network_sup(PG_FUNCTION_ARGS)
934 : : {
4507 heikki.linnakangas@i 935 : 3090 : inet *a1 = PG_GETARG_INET_PP(0);
936 : 3090 : inet *a2 = PG_GETARG_INET_PP(1);
937 : :
7600 bruce@momjian.us 938 [ + + + + : 3090 : if (ip_family(a1) == ip_family(a2))
+ + ]
939 : : {
3753 tgl@sss.pgh.pa.us 940 [ + + + + : 2490 : PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2) &&
+ + + + +
+ + + +
+ ]
941 : : bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
942 : : }
943 : :
7600 bruce@momjian.us 944 : 600 : PG_RETURN_BOOL(false);
945 : : }
946 : :
947 : : Datum
8655 tgl@sss.pgh.pa.us 948 : 9294 : network_supeq(PG_FUNCTION_ARGS)
949 : : {
4507 heikki.linnakangas@i 950 : 9294 : inet *a1 = PG_GETARG_INET_PP(0);
951 : 9294 : inet *a2 = PG_GETARG_INET_PP(1);
952 : :
7600 bruce@momjian.us 953 [ + + + + : 9294 : if (ip_family(a1) == ip_family(a2))
+ + ]
954 : : {
3753 tgl@sss.pgh.pa.us 955 [ + + + + : 5124 : PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2) &&
+ + + + +
+ + + +
+ ]
956 : : bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
957 : : }
958 : :
7600 bruce@momjian.us 959 : 4170 : PG_RETURN_BOOL(false);
960 : : }
961 : :
962 : : Datum
3659 tgl@sss.pgh.pa.us 963 : 10515 : network_overlap(PG_FUNCTION_ARGS)
964 : : {
965 : 10515 : inet *a1 = PG_GETARG_INET_PP(0);
966 : 10515 : inet *a2 = PG_GETARG_INET_PP(1);
967 : :
968 [ + - + + : 10515 : if (ip_family(a1) == ip_family(a2))
+ + ]
969 : : {
970 [ + + + - : 6399 : PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2),
+ + + - ]
971 : : Min(ip_bits(a1), ip_bits(a2))) == 0);
972 : : }
973 : :
974 : 4116 : PG_RETURN_BOOL(false);
975 : : }
976 : :
977 : : /*
978 : : * Planner support function for network subset/superset operators
979 : : */
980 : : Datum
1889 981 : 744 : network_subset_support(PG_FUNCTION_ARGS)
982 : : {
983 : 744 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
984 : 744 : Node *ret = NULL;
985 : :
986 [ + + ]: 744 : if (IsA(rawreq, SupportRequestIndexCondition))
987 : : {
988 : : /* Try to convert operator/function call to index conditions */
989 : 24 : SupportRequestIndexCondition *req = (SupportRequestIndexCondition *) rawreq;
990 : :
991 [ + - ]: 24 : if (is_opclause(req->node))
992 : : {
993 : 24 : OpExpr *clause = (OpExpr *) req->node;
994 : :
995 [ - + ]: 24 : Assert(list_length(clause->args) == 2);
996 : : ret = (Node *)
997 : 24 : match_network_function((Node *) linitial(clause->args),
998 : 24 : (Node *) lsecond(clause->args),
999 : : req->indexarg,
1000 : : req->funcid,
1001 : : req->opfamily);
1002 : : }
1889 tgl@sss.pgh.pa.us 1003 [ # # ]:UBC 0 : else if (is_funcclause(req->node)) /* be paranoid */
1004 : : {
1005 : 0 : FuncExpr *clause = (FuncExpr *) req->node;
1006 : :
1007 [ # # ]: 0 : Assert(list_length(clause->args) == 2);
1008 : : ret = (Node *)
1009 : 0 : match_network_function((Node *) linitial(clause->args),
1010 : 0 : (Node *) lsecond(clause->args),
1011 : : req->indexarg,
1012 : : req->funcid,
1013 : : req->opfamily);
1014 : : }
1015 : : }
1016 : :
1889 tgl@sss.pgh.pa.us 1017 :CBC 744 : PG_RETURN_POINTER(ret);
1018 : : }
1019 : :
1020 : : /*
1021 : : * match_network_function
1022 : : * Try to generate an indexqual for a network subset/superset function.
1023 : : *
1024 : : * This layer is just concerned with identifying the function and swapping
1025 : : * the arguments if necessary.
1026 : : */
1027 : : static List *
1028 : 24 : match_network_function(Node *leftop,
1029 : : Node *rightop,
1030 : : int indexarg,
1031 : : Oid funcid,
1032 : : Oid opfamily)
1033 : : {
1034 [ + + + + : 24 : switch (funcid)
- ]
1035 : : {
1036 : 6 : case F_NETWORK_SUB:
1037 : : /* indexkey must be on the left */
1038 [ - + ]: 6 : if (indexarg != 0)
1889 tgl@sss.pgh.pa.us 1039 :UBC 0 : return NIL;
1889 tgl@sss.pgh.pa.us 1040 :CBC 6 : return match_network_subset(leftop, rightop, false, opfamily);
1041 : :
1042 : 6 : case F_NETWORK_SUBEQ:
1043 : : /* indexkey must be on the left */
1044 [ - + ]: 6 : if (indexarg != 0)
1889 tgl@sss.pgh.pa.us 1045 :UBC 0 : return NIL;
1889 tgl@sss.pgh.pa.us 1046 :CBC 6 : return match_network_subset(leftop, rightop, true, opfamily);
1047 : :
1048 : 6 : case F_NETWORK_SUP:
1049 : : /* indexkey must be on the right */
1050 [ - + ]: 6 : if (indexarg != 1)
1889 tgl@sss.pgh.pa.us 1051 :UBC 0 : return NIL;
1889 tgl@sss.pgh.pa.us 1052 :CBC 6 : return match_network_subset(rightop, leftop, false, opfamily);
1053 : :
1054 : 6 : case F_NETWORK_SUPEQ:
1055 : : /* indexkey must be on the right */
1056 [ - + ]: 6 : if (indexarg != 1)
1889 tgl@sss.pgh.pa.us 1057 :UBC 0 : return NIL;
1889 tgl@sss.pgh.pa.us 1058 :CBC 6 : return match_network_subset(rightop, leftop, true, opfamily);
1059 : :
1889 tgl@sss.pgh.pa.us 1060 :UBC 0 : default:
1061 : :
1062 : : /*
1063 : : * We'd only get here if somebody attached this support function
1064 : : * to an unexpected function. Maybe we should complain, but for
1065 : : * now, do nothing.
1066 : : */
1067 : 0 : return NIL;
1068 : : }
1069 : : }
1070 : :
1071 : : /*
1072 : : * match_network_subset
1073 : : * Try to generate an indexqual for a network subset function.
1074 : : */
1075 : : static List *
1889 tgl@sss.pgh.pa.us 1076 :CBC 24 : match_network_subset(Node *leftop,
1077 : : Node *rightop,
1078 : : bool is_eq,
1079 : : Oid opfamily)
1080 : : {
1081 : : List *result;
1082 : : Datum rightopval;
1083 : 24 : Oid datatype = INETOID;
1084 : : Oid opr1oid;
1085 : : Oid opr2oid;
1086 : : Datum opr1right;
1087 : : Datum opr2right;
1088 : : Expr *expr;
1089 : :
1090 : : /*
1091 : : * Can't do anything with a non-constant or NULL comparison value.
1092 : : *
1093 : : * Note that since we restrict ourselves to cases with a hard constant on
1094 : : * the RHS, it's a-fortiori a pseudoconstant, and we don't need to worry
1095 : : * about verifying that.
1096 : : */
1097 [ + - ]: 24 : if (!IsA(rightop, Const) ||
1098 [ - + ]: 24 : ((Const *) rightop)->constisnull)
1889 tgl@sss.pgh.pa.us 1099 :UBC 0 : return NIL;
1889 tgl@sss.pgh.pa.us 1100 :CBC 24 : rightopval = ((Const *) rightop)->constvalue;
1101 : :
1102 : : /*
1103 : : * Must check that index's opfamily supports the operators we will want to
1104 : : * apply.
1105 : : *
1106 : : * We insist on the opfamily being the specific one we expect, else we'd
1107 : : * do the wrong thing if someone were to make a reverse-sort opfamily with
1108 : : * the same operators.
1109 : : */
1110 [ - + ]: 24 : if (opfamily != NETWORK_BTREE_FAM_OID)
1889 tgl@sss.pgh.pa.us 1111 :UBC 0 : return NIL;
1112 : :
1113 : : /*
1114 : : * create clause "key >= network_scan_first( rightopval )", or ">" if the
1115 : : * operator disallows equality.
1116 : : *
1117 : : * Note: seeing that this function supports only fixed values for opfamily
1118 : : * and datatype, we could just hard-wire the operator OIDs instead of
1119 : : * looking them up. But for now it seems better to be general.
1120 : : */
1889 tgl@sss.pgh.pa.us 1121 [ + + ]:CBC 24 : if (is_eq)
1122 : : {
1123 : 12 : opr1oid = get_opfamily_member(opfamily, datatype, datatype,
1124 : : BTGreaterEqualStrategyNumber);
1125 [ - + ]: 12 : if (opr1oid == InvalidOid)
1889 tgl@sss.pgh.pa.us 1126 [ # # ]:UBC 0 : elog(ERROR, "no >= operator for opfamily %u", opfamily);
1127 : : }
1128 : : else
1129 : : {
1889 tgl@sss.pgh.pa.us 1130 :CBC 12 : opr1oid = get_opfamily_member(opfamily, datatype, datatype,
1131 : : BTGreaterStrategyNumber);
1132 [ - + ]: 12 : if (opr1oid == InvalidOid)
1889 tgl@sss.pgh.pa.us 1133 [ # # ]:UBC 0 : elog(ERROR, "no > operator for opfamily %u", opfamily);
1134 : : }
1135 : :
1889 tgl@sss.pgh.pa.us 1136 :CBC 24 : opr1right = network_scan_first(rightopval);
1137 : :
1138 : 24 : expr = make_opclause(opr1oid, BOOLOID, false,
1139 : : (Expr *) leftop,
1140 : 24 : (Expr *) makeConst(datatype, -1,
1141 : : InvalidOid, /* not collatable */
1142 : : -1, opr1right,
1143 : : false, false),
1144 : : InvalidOid, InvalidOid);
1145 : 24 : result = list_make1(expr);
1146 : :
1147 : : /* create clause "key <= network_scan_last( rightopval )" */
1148 : :
1149 : 24 : opr2oid = get_opfamily_member(opfamily, datatype, datatype,
1150 : : BTLessEqualStrategyNumber);
1151 [ - + ]: 24 : if (opr2oid == InvalidOid)
1889 tgl@sss.pgh.pa.us 1152 [ # # ]:UBC 0 : elog(ERROR, "no <= operator for opfamily %u", opfamily);
1153 : :
1889 tgl@sss.pgh.pa.us 1154 :CBC 24 : opr2right = network_scan_last(rightopval);
1155 : :
1156 : 24 : expr = make_opclause(opr2oid, BOOLOID, false,
1157 : : (Expr *) leftop,
1158 : 24 : (Expr *) makeConst(datatype, -1,
1159 : : InvalidOid, /* not collatable */
1160 : : -1, opr2right,
1161 : : false, false),
1162 : : InvalidOid, InvalidOid);
1163 : 24 : result = lappend(result, expr);
1164 : :
1165 : 24 : return result;
1166 : : }
1167 : :
1168 : :
1169 : : /*
1170 : : * Extract data from a network datatype.
1171 : : */
1172 : : Datum
8683 1173 : 51 : network_host(PG_FUNCTION_ARGS)
1174 : : {
4507 heikki.linnakangas@i 1175 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1176 : : char *ptr;
1177 : : char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1178 : :
1179 : : /* force display of max bits, regardless of masklen... */
1701 tgl@sss.pgh.pa.us 1180 [ + - + + : 51 : if (pg_inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
+ - + - -
+ ]
1181 : : tmp, sizeof(tmp)) == NULL)
7567 tgl@sss.pgh.pa.us 1182 [ # # ]:UBC 0 : ereport(ERROR,
1183 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1184 : : errmsg("could not format inet value: %m")));
1185 : :
1186 : : /* Suppress /n if present (shouldn't happen now) */
9306 bruce@momjian.us 1187 [ - + ]:CBC 51 : if ((ptr = strchr(tmp, '/')) != NULL)
8683 tgl@sss.pgh.pa.us 1188 :UBC 0 : *ptr = '\0';
1189 : :
5864 tgl@sss.pgh.pa.us 1190 :CBC 51 : PG_RETURN_TEXT_P(cstring_to_text(tmp));
1191 : : }
1192 : :
1193 : : /*
1194 : : * network_show implements the inet and cidr casts to text. This is not
1195 : : * quite the same behavior as network_out, hence we can't drop it in favor
1196 : : * of CoerceViaIO.
1197 : : */
1198 : : Datum
8556 1199 : 106 : network_show(PG_FUNCTION_ARGS)
1200 : : {
4507 heikki.linnakangas@i 1201 : 106 : inet *ip = PG_GETARG_INET_PP(0);
1202 : : int len;
1203 : : char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1204 : :
1701 tgl@sss.pgh.pa.us 1205 [ + + + + : 106 : if (pg_inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
+ + + + -
+ ]
1206 : : tmp, sizeof(tmp)) == NULL)
7567 tgl@sss.pgh.pa.us 1207 [ # # ]:UBC 0 : ereport(ERROR,
1208 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1209 : : errmsg("could not format inet value: %m")));
1210 : :
1211 : : /* Add /n if not present (which it won't be) */
7600 bruce@momjian.us 1212 [ + - ]:CBC 106 : if (strchr(tmp, '/') == NULL)
1213 : : {
1214 : 106 : len = strlen(tmp);
1215 [ + + ]: 106 : snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
1216 : : }
1217 : :
5864 tgl@sss.pgh.pa.us 1218 : 106 : PG_RETURN_TEXT_P(cstring_to_text(tmp));
1219 : : }
1220 : :
1221 : : Datum
6653 tgl@sss.pgh.pa.us 1222 :UBC 0 : inet_abbrev(PG_FUNCTION_ARGS)
1223 : : {
4507 heikki.linnakangas@i 1224 : 0 : inet *ip = PG_GETARG_INET_PP(0);
1225 : : char *dst;
1226 : : char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1227 : :
1701 tgl@sss.pgh.pa.us 1228 [ # # ]: 0 : dst = pg_inet_net_ntop(ip_family(ip), ip_addr(ip),
1229 [ # # # # ]: 0 : ip_bits(ip), tmp, sizeof(tmp));
1230 : :
7600 bruce@momjian.us 1231 [ # # ]: 0 : if (dst == NULL)
7567 tgl@sss.pgh.pa.us 1232 [ # # ]: 0 : ereport(ERROR,
1233 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1234 : : errmsg("could not format inet value: %m")));
1235 : :
5864 1236 : 0 : PG_RETURN_TEXT_P(cstring_to_text(tmp));
1237 : : }
1238 : :
1239 : : Datum
6653 tgl@sss.pgh.pa.us 1240 :CBC 51 : cidr_abbrev(PG_FUNCTION_ARGS)
1241 : : {
4507 heikki.linnakangas@i 1242 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1243 : : char *dst;
1244 : : char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1245 : :
1701 tgl@sss.pgh.pa.us 1246 [ + - ]: 51 : dst = pg_inet_cidr_ntop(ip_family(ip), ip_addr(ip),
1247 [ + - + - ]: 51 : ip_bits(ip), tmp, sizeof(tmp));
1248 : :
6653 1249 [ - + ]: 51 : if (dst == NULL)
6653 tgl@sss.pgh.pa.us 1250 [ # # ]:UBC 0 : ereport(ERROR,
1251 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1252 : : errmsg("could not format cidr value: %m")));
1253 : :
5864 tgl@sss.pgh.pa.us 1254 :CBC 51 : PG_RETURN_TEXT_P(cstring_to_text(tmp));
1255 : : }
1256 : :
1257 : : Datum
8655 1258 : 177 : network_masklen(PG_FUNCTION_ARGS)
1259 : : {
4507 heikki.linnakangas@i 1260 : 177 : inet *ip = PG_GETARG_INET_PP(0);
1261 : :
8655 tgl@sss.pgh.pa.us 1262 [ + - ]: 177 : PG_RETURN_INT32(ip_bits(ip));
1263 : : }
1264 : :
1265 : : Datum
7600 bruce@momjian.us 1266 : 51 : network_family(PG_FUNCTION_ARGS)
1267 : : {
4507 heikki.linnakangas@i 1268 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1269 : :
7559 bruce@momjian.us 1270 [ + - + + : 51 : switch (ip_family(ip))
- ]
1271 : : {
1272 : 42 : case PGSQL_AF_INET:
1273 : 42 : PG_RETURN_INT32(4);
1274 : : break;
1275 : 9 : case PGSQL_AF_INET6:
1276 : 9 : PG_RETURN_INT32(6);
1277 : : break;
7559 bruce@momjian.us 1278 :UBC 0 : default:
1279 : 0 : PG_RETURN_INT32(0);
1280 : : break;
1281 : : }
1282 : : }
1283 : :
1284 : : Datum
8683 tgl@sss.pgh.pa.us 1285 :CBC 126 : network_broadcast(PG_FUNCTION_ARGS)
1286 : : {
4507 heikki.linnakangas@i 1287 : 126 : inet *ip = PG_GETARG_INET_PP(0);
1288 : : inet *dst;
1289 : : int byte;
1290 : : int bits;
1291 : : int maxbytes;
1292 : : unsigned char mask;
1293 : : unsigned char *a,
1294 : : *b;
1295 : :
1296 : : /* make sure any unused bits are zeroed */
6218 tgl@sss.pgh.pa.us 1297 : 126 : dst = (inet *) palloc0(sizeof(inet));
1298 : :
2791 1299 [ + + + + ]: 126 : maxbytes = ip_addrsize(ip);
7600 bruce@momjian.us 1300 [ + + ]: 126 : bits = ip_bits(ip);
1301 [ + + ]: 126 : a = ip_addr(ip);
1302 [ - + ]: 126 : b = ip_addr(dst);
1303 : :
4753 1304 [ + + ]: 846 : for (byte = 0; byte < maxbytes; byte++)
1305 : : {
7559 1306 [ + + ]: 720 : if (bits >= 8)
1307 : : {
7600 1308 : 495 : mask = 0x00;
1309 : 495 : bits -= 8;
1310 : : }
7559 1311 [ + + ]: 225 : else if (bits == 0)
7600 1312 : 213 : mask = 0xff;
1313 : : else
1314 : : {
1315 : 12 : mask = 0xff >> bits;
1316 : 12 : bits = 0;
1317 : : }
1318 : :
4753 1319 : 720 : b[byte] = a[byte] | mask;
1320 : : }
1321 : :
8556 tgl@sss.pgh.pa.us 1322 [ + + - + ]: 126 : ip_family(dst) = ip_family(ip);
1323 [ + + - + ]: 126 : ip_bits(dst) = ip_bits(ip);
6218 1324 [ - + + + ]: 126 : SET_INET_VARSIZE(dst);
1325 : :
8556 1326 : 126 : PG_RETURN_INET_P(dst);
1327 : : }
1328 : :
1329 : : Datum
8683 1330 : 126 : network_network(PG_FUNCTION_ARGS)
1331 : : {
4507 heikki.linnakangas@i 1332 : 126 : inet *ip = PG_GETARG_INET_PP(0);
1333 : : inet *dst;
1334 : : int byte;
1335 : : int bits;
1336 : : unsigned char mask;
1337 : : unsigned char *a,
1338 : : *b;
1339 : :
1340 : : /* make sure any unused bits are zeroed */
6218 tgl@sss.pgh.pa.us 1341 : 126 : dst = (inet *) palloc0(sizeof(inet));
1342 : :
7600 bruce@momjian.us 1343 [ + + ]: 126 : bits = ip_bits(ip);
1344 [ + + ]: 126 : a = ip_addr(ip);
1345 [ - + ]: 126 : b = ip_addr(dst);
1346 : :
1347 : 126 : byte = 0;
1348 : :
7559 1349 [ + + ]: 633 : while (bits)
1350 : : {
1351 [ + + ]: 507 : if (bits >= 8)
1352 : : {
7600 1353 : 495 : mask = 0xff;
1354 : 495 : bits -= 8;
1355 : : }
1356 : : else
1357 : : {
1358 : 12 : mask = 0xff << (8 - bits);
1359 : 12 : bits = 0;
1360 : : }
1361 : :
4753 1362 : 507 : b[byte] = a[byte] & mask;
1363 : 507 : byte++;
1364 : : }
1365 : :
8556 tgl@sss.pgh.pa.us 1366 [ + + - + ]: 126 : ip_family(dst) = ip_family(ip);
1367 [ + + - + ]: 126 : ip_bits(dst) = ip_bits(ip);
6218 1368 [ - + + + ]: 126 : SET_INET_VARSIZE(dst);
1369 : :
8556 1370 : 126 : PG_RETURN_INET_P(dst);
1371 : : }
1372 : :
1373 : : Datum
8683 tgl@sss.pgh.pa.us 1374 :UBC 0 : network_netmask(PG_FUNCTION_ARGS)
1375 : : {
4507 heikki.linnakangas@i 1376 : 0 : inet *ip = PG_GETARG_INET_PP(0);
1377 : : inet *dst;
1378 : : int byte;
1379 : : int bits;
1380 : : unsigned char mask;
1381 : : unsigned char *b;
1382 : :
1383 : : /* make sure any unused bits are zeroed */
6218 tgl@sss.pgh.pa.us 1384 : 0 : dst = (inet *) palloc0(sizeof(inet));
1385 : :
7600 bruce@momjian.us 1386 [ # # ]: 0 : bits = ip_bits(ip);
1387 [ # # ]: 0 : b = ip_addr(dst);
1388 : :
1389 : 0 : byte = 0;
1390 : :
7559 1391 [ # # ]: 0 : while (bits)
1392 : : {
1393 [ # # ]: 0 : if (bits >= 8)
1394 : : {
7600 1395 : 0 : mask = 0xff;
1396 : 0 : bits -= 8;
1397 : : }
1398 : : else
1399 : : {
1400 : 0 : mask = 0xff << (8 - bits);
1401 : 0 : bits = 0;
1402 : : }
1403 : :
1404 : 0 : b[byte] = mask;
4753 1405 : 0 : byte++;
1406 : : }
1407 : :
8556 tgl@sss.pgh.pa.us 1408 [ # # # # ]: 0 : ip_family(dst) = ip_family(ip);
7440 1409 [ # # # # : 0 : ip_bits(dst) = ip_maxbits(ip);
# # ]
6218 1410 [ # # # # ]: 0 : SET_INET_VARSIZE(dst);
1411 : :
8556 1412 : 0 : PG_RETURN_INET_P(dst);
1413 : : }
1414 : :
1415 : : Datum
7695 bruce@momjian.us 1416 : 0 : network_hostmask(PG_FUNCTION_ARGS)
1417 : : {
4507 heikki.linnakangas@i 1418 : 0 : inet *ip = PG_GETARG_INET_PP(0);
1419 : : inet *dst;
1420 : : int byte;
1421 : : int bits;
1422 : : int maxbytes;
1423 : : unsigned char mask;
1424 : : unsigned char *b;
1425 : :
1426 : : /* make sure any unused bits are zeroed */
6218 tgl@sss.pgh.pa.us 1427 : 0 : dst = (inet *) palloc0(sizeof(inet));
1428 : :
2791 1429 [ # # # # ]: 0 : maxbytes = ip_addrsize(ip);
7600 bruce@momjian.us 1430 [ # # # # : 0 : bits = ip_maxbits(ip) - ip_bits(ip);
# # ]
1431 [ # # ]: 0 : b = ip_addr(dst);
1432 : :
1433 : 0 : byte = maxbytes - 1;
1434 : :
7559 1435 [ # # ]: 0 : while (bits)
1436 : : {
1437 [ # # ]: 0 : if (bits >= 8)
1438 : : {
7600 1439 : 0 : mask = 0xff;
1440 : 0 : bits -= 8;
1441 : : }
1442 : : else
1443 : : {
1444 : 0 : mask = 0xff >> (8 - bits);
1445 : 0 : bits = 0;
1446 : : }
1447 : :
1448 : 0 : b[byte] = mask;
4753 1449 : 0 : byte--;
1450 : : }
1451 : :
7695 1452 [ # # # # ]: 0 : ip_family(dst) = ip_family(ip);
7440 tgl@sss.pgh.pa.us 1453 [ # # # # : 0 : ip_bits(dst) = ip_maxbits(ip);
# # ]
6218 1454 [ # # # # ]: 0 : SET_INET_VARSIZE(dst);
1455 : :
7695 bruce@momjian.us 1456 : 0 : PG_RETURN_INET_P(dst);
1457 : : }
1458 : :
1459 : : /*
1460 : : * Returns true if the addresses are from the same family, or false. Used to
1461 : : * check that we can create a network which contains both of the networks.
1462 : : */
1463 : : Datum
3267 alvherre@alvh.no-ip. 1464 :CBC 120 : inet_same_family(PG_FUNCTION_ARGS)
1465 : : {
1466 : 120 : inet *a1 = PG_GETARG_INET_PP(0);
1467 : 120 : inet *a2 = PG_GETARG_INET_PP(1);
1468 : :
1469 [ + + + - ]: 120 : PG_RETURN_BOOL(ip_family(a1) == ip_family(a2));
1470 : : }
1471 : :
1472 : : /*
1473 : : * Returns the smallest CIDR which contains both of the inputs.
1474 : : */
1475 : : Datum
1476 : 117 : inet_merge(PG_FUNCTION_ARGS)
1477 : : {
1478 : 117 : inet *a1 = PG_GETARG_INET_PP(0),
2791 tgl@sss.pgh.pa.us 1479 : 117 : *a2 = PG_GETARG_INET_PP(1);
1480 : : int commonbits;
1481 : :
3267 alvherre@alvh.no-ip. 1482 [ + + + - : 117 : if (ip_family(a1) != ip_family(a2))
+ + ]
1483 [ + - ]: 3 : ereport(ERROR,
1484 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1485 : : errmsg("cannot merge addresses from different families")));
1486 : :
1487 [ + + ]: 114 : commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
1488 [ + - + + : 114 : Min(ip_bits(a1), ip_bits(a2)));
+ - ]
1489 : :
2791 tgl@sss.pgh.pa.us 1490 : 114 : PG_RETURN_INET_P(cidr_set_masklen_internal(a1, commonbits));
1491 : : }
1492 : :
1493 : : /*
1494 : : * Convert a value of a network datatype to an approximate scalar value.
1495 : : * This is used for estimating selectivities of inequality operators
1496 : : * involving network types.
1497 : : *
1498 : : * On failure (e.g., unsupported typid), set *failure to true;
1499 : : * otherwise, that variable is not changed.
1500 : : */
1501 : : double
2234 1502 : 5440 : convert_network_to_scalar(Datum value, Oid typid, bool *failure)
1503 : : {
8345 1504 [ + - - - ]: 5440 : switch (typid)
1505 : : {
1506 : 5440 : case INETOID:
1507 : : case CIDROID:
1508 : : {
4541 heikki.linnakangas@i 1509 : 5440 : inet *ip = DatumGetInetPP(value);
1510 : : int len;
1511 : : double res;
1512 : : int i;
1513 : :
1514 : : /*
1515 : : * Note that we don't use the full address for IPv6.
1516 : : */
7600 bruce@momjian.us 1517 [ + + + - ]: 5440 : if (ip_family(ip) == PGSQL_AF_INET)
1518 : 5440 : len = 4;
1519 : : else
7600 bruce@momjian.us 1520 :UBC 0 : len = 5;
1521 : :
7600 bruce@momjian.us 1522 [ + + ]:CBC 5440 : res = ip_family(ip);
7559 1523 [ + + ]: 27200 : for (i = 0; i < len; i++)
1524 : : {
7600 1525 : 21760 : res *= 256;
1526 [ + + ]: 21760 : res += ip_addr(ip)[i];
1527 : : }
1528 : 5440 : return res;
1529 : : }
8345 tgl@sss.pgh.pa.us 1530 :UBC 0 : case MACADDROID:
1531 : : {
8207 bruce@momjian.us 1532 : 0 : macaddr *mac = DatumGetMacaddrP(value);
1533 : : double res;
1534 : :
1535 : 0 : res = (mac->a << 16) | (mac->b << 8) | (mac->c);
1536 : 0 : res *= 256 * 256 * 256;
1537 : 0 : res += (mac->d << 16) | (mac->e << 8) | (mac->f);
1538 : 0 : return res;
1539 : : }
2587 sfrost@snowman.net 1540 : 0 : case MACADDR8OID:
1541 : : {
1542 : 0 : macaddr8 *mac = DatumGetMacaddr8P(value);
1543 : : double res;
1544 : :
1545 : 0 : res = (mac->a << 24) | (mac->b << 16) | (mac->c << 8) | (mac->d);
1546 : 0 : res *= ((double) 256) * 256 * 256 * 256;
1547 : 0 : res += (mac->e << 24) | (mac->f << 16) | (mac->g << 8) | (mac->h);
1548 : 0 : return res;
1549 : : }
1550 : : }
1551 : :
2234 tgl@sss.pgh.pa.us 1552 : 0 : *failure = true;
8345 1553 : 0 : return 0;
1554 : : }
1555 : :
1556 : : /*
1557 : : * int
1558 : : * bitncmp(l, r, n)
1559 : : * compare bit masks l and r, for n bits.
1560 : : * return:
1561 : : * <0, >0, or 0 in the libc tradition.
1562 : : * note:
1563 : : * network byte order assumed. this means 192.5.5.240/28 has
1564 : : * 0x11110000 in its fourth octet.
1565 : : * author:
1566 : : * Paul Vixie (ISC), June 1996
1567 : : */
1568 : : int
3659 tgl@sss.pgh.pa.us 1569 :CBC 205391 : bitncmp(const unsigned char *l, const unsigned char *r, int n)
1570 : : {
1571 : : unsigned int lb,
1572 : : rb;
1573 : : int x,
1574 : : b;
1575 : :
7600 bruce@momjian.us 1576 : 205391 : b = n / 8;
1577 : 205391 : x = memcmp(l, r, b);
5302 heikki.linnakangas@i 1578 [ + + + + ]: 205391 : if (x || (n % 8) == 0)
6668 neilc@samurai.com 1579 : 205246 : return x;
1580 : :
3659 tgl@sss.pgh.pa.us 1581 : 145 : lb = l[b];
1582 : 145 : rb = r[b];
7559 bruce@momjian.us 1583 [ + + ]: 251 : for (b = n % 8; b > 0; b--)
1584 : : {
6685 1585 [ + + ]: 172 : if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb))
1586 : : {
1587 [ + + ]: 66 : if (IS_HIGHBIT_SET(lb))
1588 : 30 : return 1;
1589 : 36 : return -1;
1590 : : }
7600 1591 : 106 : lb <<= 1;
1592 : 106 : rb <<= 1;
1593 : : }
6685 1594 : 79 : return 0;
1595 : : }
1596 : :
1597 : : /*
1598 : : * bitncommon: compare bit masks l and r, for up to n bits.
1599 : : *
1600 : : * Returns the number of leading bits that match (0 to n).
1601 : : */
1602 : : int
3659 tgl@sss.pgh.pa.us 1603 : 1660 : bitncommon(const unsigned char *l, const unsigned char *r, int n)
1604 : : {
1605 : : int byte,
1606 : : nbits;
1607 : :
1608 : : /* number of bits to examine in last byte */
1609 : 1660 : nbits = n % 8;
1610 : :
1611 : : /* check whole bytes */
1612 [ + + ]: 2165 : for (byte = 0; byte < n / 8; byte++)
1613 : : {
1614 [ + + ]: 533 : if (l[byte] != r[byte])
1615 : : {
1616 : : /* at least one bit in the last byte is not common */
1617 : 28 : nbits = 7;
1618 : 28 : break;
1619 : : }
1620 : : }
1621 : :
1622 : : /* check bits in last partial byte */
1623 [ + + ]: 1660 : if (nbits != 0)
1624 : : {
1625 : : /* calculate diff of first non-matching bytes */
1626 : 1282 : unsigned int diff = l[byte] ^ r[byte];
1627 : :
1628 : : /* compare the bits from the most to the least */
1629 [ + + ]: 1512 : while ((diff >> (8 - nbits)) != 0)
1630 : 230 : nbits--;
1631 : : }
1632 : :
1633 : 1660 : return (8 * byte) + nbits;
1634 : : }
1635 : :
1636 : :
1637 : : /*
1638 : : * Verify a CIDR address is OK (doesn't have bits set past the masklen)
1639 : : */
1640 : : static bool
7600 bruce@momjian.us 1641 : 690 : addressOK(unsigned char *a, int bits, int family)
1642 : : {
1643 : : int byte;
1644 : : int nbits;
1645 : : int maxbits;
1646 : : int maxbytes;
1647 : : unsigned char mask;
1648 : :
7559 1649 [ + + ]: 690 : if (family == PGSQL_AF_INET)
1650 : : {
7600 1651 : 549 : maxbits = 32;
1652 : 549 : maxbytes = 4;
1653 : : }
1654 : : else
1655 : : {
1656 : 141 : maxbits = 128;
1657 : 141 : maxbytes = 16;
1658 : : }
7562 tgl@sss.pgh.pa.us 1659 [ - + ]: 690 : Assert(bits <= maxbits);
1660 : :
7600 bruce@momjian.us 1661 [ + + ]: 690 : if (bits == maxbits)
7562 tgl@sss.pgh.pa.us 1662 : 301 : return true;
1663 : :
7128 bruce@momjian.us 1664 : 389 : byte = bits / 8;
1665 : :
7600 1666 : 389 : nbits = bits % 8;
1667 : 389 : mask = 0xff;
1668 [ + + ]: 389 : if (bits != 0)
1669 : 365 : mask >>= nbits;
1670 : :
4753 1671 [ + + ]: 1501 : while (byte < maxbytes)
1672 : : {
1673 [ + + ]: 1127 : if ((a[byte] & mask) != 0)
7562 tgl@sss.pgh.pa.us 1674 : 15 : return false;
7600 bruce@momjian.us 1675 : 1112 : mask = 0xff;
4753 1676 : 1112 : byte++;
1677 : : }
1678 : :
7562 tgl@sss.pgh.pa.us 1679 : 374 : return true;
1680 : : }
1681 : :
1682 : :
1683 : : /*
1684 : : * These functions are used by planner to generate indexscan limits
1685 : : * for clauses a << b and a <<= b
1686 : : */
1687 : :
1688 : : /* return the minimal value for an IP on a given network */
1689 : : Datum
8337 1690 : 24 : network_scan_first(Datum in)
1691 : : {
1692 : 24 : return DirectFunctionCall1(network_network, in);
1693 : : }
1694 : :
1695 : : /*
1696 : : * return "last" IP on a given network. It's the broadcast address,
1697 : : * however, masklen has to be set to its max bits, since
1698 : : * 192.168.0.255/24 is considered less than 192.168.0.255/32
1699 : : *
1700 : : * inet_set_masklen() hacked to max out the masklength to 128 for IPv6
1701 : : * and 32 for IPv4 when given '-1' as argument.
1702 : : */
1703 : : Datum
1704 : 24 : network_scan_last(Datum in)
1705 : : {
1706 : 24 : return DirectFunctionCall2(inet_set_masklen,
1707 : : DirectFunctionCall1(network_broadcast, in),
1708 : : Int32GetDatum(-1));
1709 : : }
1710 : :
1711 : :
1712 : : /*
1713 : : * IP address that the client is connecting from (NULL if Unix socket)
1714 : : */
1715 : : Datum
7245 tgl@sss.pgh.pa.us 1716 :UBC 0 : inet_client_addr(PG_FUNCTION_ARGS)
1717 : : {
7168 bruce@momjian.us 1718 : 0 : Port *port = MyProcPort;
1719 : : char remote_host[NI_MAXHOST];
1720 : : int ret;
1721 : :
7245 tgl@sss.pgh.pa.us 1722 [ # # ]: 0 : if (port == NULL)
1723 : 0 : PG_RETURN_NULL();
1724 : :
7168 bruce@momjian.us 1725 [ # # ]: 0 : switch (port->raddr.addr.ss_family)
1726 : : {
1727 : 0 : case AF_INET:
1728 : : case AF_INET6:
1729 : 0 : break;
1730 : 0 : default:
1731 : 0 : PG_RETURN_NULL();
1732 : : }
1733 : :
7245 tgl@sss.pgh.pa.us 1734 : 0 : remote_host[0] = '\0';
1735 : :
6754 1736 : 0 : ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1737 : : remote_host, sizeof(remote_host),
1738 : : NULL, 0,
1739 : : NI_NUMERICHOST | NI_NUMERICSERV);
4632 peter_e@gmx.net 1740 [ # # ]: 0 : if (ret != 0)
7245 tgl@sss.pgh.pa.us 1741 : 0 : PG_RETURN_NULL();
1742 : :
6177 1743 : 0 : clean_ipv6_addr(port->raddr.addr.ss_family, remote_host);
1744 : :
487 1745 : 0 : PG_RETURN_INET_P(network_in(remote_host, false, NULL));
1746 : : }
1747 : :
1748 : :
1749 : : /*
1750 : : * port that the client is connecting from (NULL if Unix socket)
1751 : : */
1752 : : Datum
7245 1753 : 0 : inet_client_port(PG_FUNCTION_ARGS)
1754 : : {
7168 bruce@momjian.us 1755 : 0 : Port *port = MyProcPort;
1756 : : char remote_port[NI_MAXSERV];
1757 : : int ret;
1758 : :
7245 tgl@sss.pgh.pa.us 1759 [ # # ]: 0 : if (port == NULL)
1760 : 0 : PG_RETURN_NULL();
1761 : :
7168 bruce@momjian.us 1762 [ # # ]: 0 : switch (port->raddr.addr.ss_family)
1763 : : {
1764 : 0 : case AF_INET:
1765 : : case AF_INET6:
1766 : 0 : break;
1767 : 0 : default:
1768 : 0 : PG_RETURN_NULL();
1769 : : }
1770 : :
7245 tgl@sss.pgh.pa.us 1771 : 0 : remote_port[0] = '\0';
1772 : :
6754 1773 : 0 : ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1774 : : NULL, 0,
1775 : : remote_port, sizeof(remote_port),
1776 : : NI_NUMERICHOST | NI_NUMERICSERV);
4632 peter_e@gmx.net 1777 [ # # ]: 0 : if (ret != 0)
7245 tgl@sss.pgh.pa.us 1778 : 0 : PG_RETURN_NULL();
1779 : :
1780 : 0 : PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));
1781 : : }
1782 : :
1783 : :
1784 : : /*
1785 : : * IP address that the server accepted the connection on (NULL if Unix socket)
1786 : : */
1787 : : Datum
1788 : 0 : inet_server_addr(PG_FUNCTION_ARGS)
1789 : : {
7168 bruce@momjian.us 1790 : 0 : Port *port = MyProcPort;
1791 : : char local_host[NI_MAXHOST];
1792 : : int ret;
1793 : :
7245 tgl@sss.pgh.pa.us 1794 [ # # ]: 0 : if (port == NULL)
1795 : 0 : PG_RETURN_NULL();
1796 : :
7168 bruce@momjian.us 1797 [ # # ]: 0 : switch (port->laddr.addr.ss_family)
1798 : : {
1799 : 0 : case AF_INET:
1800 : : case AF_INET6:
1801 : 0 : break;
1802 : 0 : default:
1803 : 0 : PG_RETURN_NULL();
1804 : : }
1805 : :
7245 tgl@sss.pgh.pa.us 1806 : 0 : local_host[0] = '\0';
1807 : :
6754 1808 : 0 : ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen,
1809 : : local_host, sizeof(local_host),
1810 : : NULL, 0,
1811 : : NI_NUMERICHOST | NI_NUMERICSERV);
4632 peter_e@gmx.net 1812 [ # # ]: 0 : if (ret != 0)
7245 tgl@sss.pgh.pa.us 1813 : 0 : PG_RETURN_NULL();
1814 : :
6177 1815 : 0 : clean_ipv6_addr(port->laddr.addr.ss_family, local_host);
1816 : :
487 1817 : 0 : PG_RETURN_INET_P(network_in(local_host, false, NULL));
1818 : : }
1819 : :
1820 : :
1821 : : /*
1822 : : * port that the server accepted the connection on (NULL if Unix socket)
1823 : : */
1824 : : Datum
7245 1825 : 0 : inet_server_port(PG_FUNCTION_ARGS)
1826 : : {
7168 bruce@momjian.us 1827 : 0 : Port *port = MyProcPort;
1828 : : char local_port[NI_MAXSERV];
1829 : : int ret;
1830 : :
7245 tgl@sss.pgh.pa.us 1831 [ # # ]: 0 : if (port == NULL)
1832 : 0 : PG_RETURN_NULL();
1833 : :
7168 bruce@momjian.us 1834 [ # # ]: 0 : switch (port->laddr.addr.ss_family)
1835 : : {
1836 : 0 : case AF_INET:
1837 : : case AF_INET6:
1838 : 0 : break;
1839 : 0 : default:
1840 : 0 : PG_RETURN_NULL();
1841 : : }
1842 : :
7245 tgl@sss.pgh.pa.us 1843 : 0 : local_port[0] = '\0';
1844 : :
6754 1845 : 0 : ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen,
1846 : : NULL, 0,
1847 : : local_port, sizeof(local_port),
1848 : : NI_NUMERICHOST | NI_NUMERICSERV);
4632 peter_e@gmx.net 1849 [ # # ]: 0 : if (ret != 0)
7245 tgl@sss.pgh.pa.us 1850 : 0 : PG_RETURN_NULL();
1851 : :
1852 : 0 : PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port)));
1853 : : }
1854 : :
1855 : :
1856 : : Datum
6637 bruce@momjian.us 1857 :CBC 51 : inetnot(PG_FUNCTION_ARGS)
1858 : : {
4507 heikki.linnakangas@i 1859 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1860 : : inet *dst;
1861 : :
6218 tgl@sss.pgh.pa.us 1862 : 51 : dst = (inet *) palloc0(sizeof(inet));
1863 : :
1864 : : {
6402 bruce@momjian.us 1865 [ + - + + ]: 51 : int nb = ip_addrsize(ip);
1866 [ + - ]: 51 : unsigned char *pip = ip_addr(ip);
1867 [ - + ]: 51 : unsigned char *pdst = ip_addr(dst);
1868 : :
395 andres@anarazel.de 1869 [ + + ]: 363 : while (--nb >= 0)
6637 bruce@momjian.us 1870 : 312 : pdst[nb] = ~pip[nb];
1871 : : }
1872 [ + - - + ]: 51 : ip_bits(dst) = ip_bits(ip);
1873 : :
1874 [ + - - + ]: 51 : ip_family(dst) = ip_family(ip);
6218 tgl@sss.pgh.pa.us 1875 [ - + + + ]: 51 : SET_INET_VARSIZE(dst);
1876 : :
6637 bruce@momjian.us 1877 : 51 : PG_RETURN_INET_P(dst);
1878 : : }
1879 : :
1880 : :
1881 : : Datum
1882 : 51 : inetand(PG_FUNCTION_ARGS)
1883 : : {
4507 heikki.linnakangas@i 1884 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1885 : 51 : inet *ip2 = PG_GETARG_INET_PP(1);
1886 : : inet *dst;
1887 : :
6218 tgl@sss.pgh.pa.us 1888 : 51 : dst = (inet *) palloc0(sizeof(inet));
1889 : :
6637 bruce@momjian.us 1890 [ + - + - : 51 : if (ip_family(ip) != ip_family(ip2))
- + ]
6637 bruce@momjian.us 1891 [ # # ]:UBC 0 : ereport(ERROR,
1892 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1893 : : errmsg("cannot AND inet values of different sizes")));
1894 : : else
1895 : : {
6402 bruce@momjian.us 1896 [ + - + + ]:CBC 51 : int nb = ip_addrsize(ip);
1897 [ + - ]: 51 : unsigned char *pip = ip_addr(ip);
1898 [ + - ]: 51 : unsigned char *pip2 = ip_addr(ip2);
1899 [ - + ]: 51 : unsigned char *pdst = ip_addr(dst);
1900 : :
395 andres@anarazel.de 1901 [ + + ]: 363 : while (--nb >= 0)
6637 bruce@momjian.us 1902 : 312 : pdst[nb] = pip[nb] & pip2[nb];
1903 : : }
1904 [ + - + - : 51 : ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
- + ]
1905 : :
1906 [ + - - + ]: 51 : ip_family(dst) = ip_family(ip);
6218 tgl@sss.pgh.pa.us 1907 [ - + + + ]: 51 : SET_INET_VARSIZE(dst);
1908 : :
6637 bruce@momjian.us 1909 : 51 : PG_RETURN_INET_P(dst);
1910 : : }
1911 : :
1912 : :
1913 : : Datum
1914 : 51 : inetor(PG_FUNCTION_ARGS)
1915 : : {
4507 heikki.linnakangas@i 1916 : 51 : inet *ip = PG_GETARG_INET_PP(0);
1917 : 51 : inet *ip2 = PG_GETARG_INET_PP(1);
1918 : : inet *dst;
1919 : :
6218 tgl@sss.pgh.pa.us 1920 : 51 : dst = (inet *) palloc0(sizeof(inet));
1921 : :
6637 bruce@momjian.us 1922 [ + - + - : 51 : if (ip_family(ip) != ip_family(ip2))
- + ]
6637 bruce@momjian.us 1923 [ # # ]:UBC 0 : ereport(ERROR,
1924 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1925 : : errmsg("cannot OR inet values of different sizes")));
1926 : : else
1927 : : {
6402 bruce@momjian.us 1928 [ + - + + ]:CBC 51 : int nb = ip_addrsize(ip);
1929 [ + - ]: 51 : unsigned char *pip = ip_addr(ip);
1930 [ + - ]: 51 : unsigned char *pip2 = ip_addr(ip2);
1931 [ - + ]: 51 : unsigned char *pdst = ip_addr(dst);
1932 : :
395 andres@anarazel.de 1933 [ + + ]: 363 : while (--nb >= 0)
6637 bruce@momjian.us 1934 : 312 : pdst[nb] = pip[nb] | pip2[nb];
1935 : : }
1936 [ + - + - : 51 : ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
- + ]
1937 : :
1938 [ + - - + ]: 51 : ip_family(dst) = ip_family(ip);
6218 tgl@sss.pgh.pa.us 1939 [ - + + + ]: 51 : SET_INET_VARSIZE(dst);
1940 : :
6637 bruce@momjian.us 1941 : 51 : PG_RETURN_INET_P(dst);
1942 : : }
1943 : :
1944 : :
1945 : : static inet *
tgl@sss.pgh.pa.us 1946 : 2571 : internal_inetpl(inet *ip, int64 addend)
1947 : : {
1948 : : inet *dst;
1949 : :
6218 1950 : 2571 : dst = (inet *) palloc0(sizeof(inet));
1951 : :
1952 : : {
6402 bruce@momjian.us 1953 [ + + + + ]: 2571 : int nb = ip_addrsize(ip);
1954 [ + + ]: 2571 : unsigned char *pip = ip_addr(ip);
1955 [ - + ]: 2571 : unsigned char *pdst = ip_addr(dst);
1956 : 2571 : int carry = 0;
1957 : :
395 andres@anarazel.de 1958 [ + + ]: 18687 : while (--nb >= 0)
1959 : : {
6637 tgl@sss.pgh.pa.us 1960 : 16116 : carry = pip[nb] + (int) (addend & 0xFF) + carry;
1961 : 16116 : pdst[nb] = (unsigned char) (carry & 0xFF);
1962 : 16116 : carry >>= 8;
1963 : :
1964 : : /*
1965 : : * We have to be careful about right-shifting addend because
1966 : : * right-shift isn't portable for negative values, while simply
1967 : : * dividing by 256 doesn't work (the standard rounding is in the
1968 : : * wrong direction, besides which there may be machines out there
1969 : : * that round the wrong way). So, explicitly clear the low-order
1970 : : * byte to remove any doubt about the correct result of the
1971 : : * division, and then divide rather than shift.
1972 : : */
1973 : 16116 : addend &= ~((int64) 0xFF);
1974 : 16116 : addend /= 0x100;
1975 : : }
1976 : :
1977 : : /*
1978 : : * At this point we should have addend and carry both zero if original
1979 : : * addend was >= 0, or addend -1 and carry 1 if original addend was <
1980 : : * 0. Anything else means overflow.
1981 : : */
1982 [ + + - + : 2571 : if (!((addend == 0 && carry == 0) ||
+ + ]
1983 [ - + ]: 63 : (addend == -1 && carry == 1)))
1984 [ + - ]: 6 : ereport(ERROR,
1985 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1986 : : errmsg("result is out of range")));
1987 : : }
1988 : :
6218 1989 [ + + - + ]: 2565 : ip_bits(dst) = ip_bits(ip);
6637 bruce@momjian.us 1990 [ + + - + ]: 2565 : ip_family(dst) = ip_family(ip);
6218 tgl@sss.pgh.pa.us 1991 [ - + + + ]: 2565 : SET_INET_VARSIZE(dst);
1992 : :
6637 1993 : 2565 : return dst;
1994 : : }
1995 : :
1996 : :
1997 : : Datum
bruce@momjian.us 1998 : 2505 : inetpl(PG_FUNCTION_ARGS)
1999 : : {
4507 heikki.linnakangas@i 2000 : 2505 : inet *ip = PG_GETARG_INET_PP(0);
6402 bruce@momjian.us 2001 : 2505 : int64 addend = PG_GETARG_INT64(1);
2002 : :
6637 tgl@sss.pgh.pa.us 2003 : 2505 : PG_RETURN_INET_P(internal_inetpl(ip, addend));
2004 : : }
2005 : :
2006 : :
2007 : : Datum
bruce@momjian.us 2008 : 66 : inetmi_int8(PG_FUNCTION_ARGS)
2009 : : {
4507 heikki.linnakangas@i 2010 : 66 : inet *ip = PG_GETARG_INET_PP(0);
6402 bruce@momjian.us 2011 : 66 : int64 addend = PG_GETARG_INT64(1);
2012 : :
6637 tgl@sss.pgh.pa.us 2013 : 66 : PG_RETURN_INET_P(internal_inetpl(ip, -addend));
2014 : : }
2015 : :
2016 : :
2017 : : Datum
bruce@momjian.us 2018 : 72 : inetmi(PG_FUNCTION_ARGS)
2019 : : {
4507 heikki.linnakangas@i 2020 : 72 : inet *ip = PG_GETARG_INET_PP(0);
2021 : 72 : inet *ip2 = PG_GETARG_INET_PP(1);
6637 bruce@momjian.us 2022 : 72 : int64 res = 0;
2023 : :
2024 [ + + + + : 72 : if (ip_family(ip) != ip_family(ip2))
- + ]
6637 bruce@momjian.us 2025 [ # # ]:UBC 0 : ereport(ERROR,
2026 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2027 : : errmsg("cannot subtract inet values of different sizes")));
2028 : : else
2029 : : {
2030 : : /*
2031 : : * We form the difference using the traditional complement, increment,
2032 : : * and add rule, with the increment part being handled by starting the
2033 : : * carry off at 1. If you don't think integer arithmetic is done in
2034 : : * two's complement, too bad.
2035 : : */
6402 bruce@momjian.us 2036 [ + + + + ]:CBC 72 : int nb = ip_addrsize(ip);
4753 2037 : 72 : int byte = 0;
6402 2038 [ + + ]: 72 : unsigned char *pip = ip_addr(ip);
2039 [ + + ]: 72 : unsigned char *pip2 = ip_addr(ip2);
2040 : 72 : int carry = 1;
2041 : :
395 andres@anarazel.de 2042 [ + + ]: 636 : while (--nb >= 0)
2043 : : {
2044 : : int lobyte;
2045 : :
6637 tgl@sss.pgh.pa.us 2046 : 570 : carry = pip[nb] + (~pip2[nb] & 0xFF) + carry;
2047 : 570 : lobyte = carry & 0xFF;
4753 bruce@momjian.us 2048 [ + + ]: 570 : if (byte < sizeof(int64))
2049 : : {
2050 : 384 : res |= ((int64) lobyte) << (byte * 8);
2051 : : }
2052 : : else
2053 : : {
2054 : : /*
2055 : : * Input wider than int64: check for overflow. All bytes to
2056 : : * the left of what will fit should be 0 or 0xFF, depending on
2057 : : * sign of the now-complete result.
2058 : : */
6637 tgl@sss.pgh.pa.us 2059 [ + + + + ]: 186 : if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0))
bruce@momjian.us 2060 [ + - ]: 6 : ereport(ERROR,
2061 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2062 : : errmsg("result is out of range")));
2063 : : }
tgl@sss.pgh.pa.us 2064 : 564 : carry >>= 8;
4753 bruce@momjian.us 2065 : 564 : byte++;
2066 : : }
2067 : :
2068 : : /*
2069 : : * If input is narrower than int64, overflow is not possible, but we
2070 : : * have to do proper sign extension.
2071 : : */
2072 [ + + + + ]: 66 : if (carry == 0 && byte < sizeof(int64))
2128 tgl@sss.pgh.pa.us 2073 : 6 : res |= ((uint64) (int64) -1) << (byte * 8);
2074 : : }
2075 : :
6637 bruce@momjian.us 2076 : 66 : PG_RETURN_INT64(res);
2077 : : }
2078 : :
2079 : :
2080 : : /*
2081 : : * clean_ipv6_addr --- remove any '%zone' part from an IPv6 address string
2082 : : *
2083 : : * XXX This should go away someday!
2084 : : *
2085 : : * This is a kluge needed because we don't yet support zones in stored inet
2086 : : * values. Since the result of getnameinfo() might include a zone spec,
2087 : : * call this to remove it anywhere we want to feed getnameinfo's output to
2088 : : * network_in. Beats failing entirely.
2089 : : *
2090 : : * An alternative approach would be to let network_in ignore %-parts for
2091 : : * itself, but that would mean we'd silently drop zone specs in user input,
2092 : : * which seems not such a good idea.
2093 : : */
2094 : : void
6177 tgl@sss.pgh.pa.us 2095 : 565 : clean_ipv6_addr(int addr_family, char *addr)
2096 : : {
2097 [ + + ]: 565 : if (addr_family == AF_INET6)
2098 : : {
5995 bruce@momjian.us 2099 : 12 : char *pct = strchr(addr, '%');
2100 : :
6177 tgl@sss.pgh.pa.us 2101 [ - + ]: 12 : if (pct)
6177 tgl@sss.pgh.pa.us 2102 :UBC 0 : *pct = '\0';
2103 : : }
6177 tgl@sss.pgh.pa.us 2104 :CBC 565 : }
|