From fbb1daed938d404f3e669a3ab499e661af2bd25e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 11 Feb 2006 20:39:59 +0000 Subject: [PATCH] Fix incorrect addition, subtraction, and overflow checking in new inet operators. --- src/backend/utils/adt/network.c | 107 ++++--- src/include/catalog/pg_proc.h | 24 +- src/test/regress/expected/inet.out | 497 ++++++++++++++++------------- src/test/regress/sql/inet.sql | 31 +- 4 files changed, 385 insertions(+), 274 deletions(-) diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 64daefa029..2624c203f7 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for the INET and CIDR types. * - * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/11 03:32:39 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.65 2006/02/11 20:39:58 tgl Exp $ * * Jon Postel RIP 16 Oct 1998 */ @@ -27,7 +27,7 @@ static int32 network_cmp_internal(inet *a1, inet *a2); static int bitncmp(void *l, void *r, int n); static bool addressOK(unsigned char *a, int bits, int family); static int ip_addrsize(inet *inetptr); -static Datum internal_inetpl(inet *ip, int64 iarg); +static inet *internal_inetpl(inet *ip, int64 addend); /* * Access macros. @@ -1292,8 +1292,7 @@ inetand(PG_FUNCTION_ARGS) if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("mismatch in address family (%d) != (%d)", - ip_family(ip), ip_family(ip2)))); + errmsg("cannot AND inet values of different sizes"))); else { int nb = ip_addrsize(ip); @@ -1327,8 +1326,7 @@ inetor(PG_FUNCTION_ARGS) if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("mismatch in address family (%d) != (%d)", - ip_family(ip), ip_family(ip2)))); + errmsg("cannot OR inet values of different sizes"))); else { int nb = ip_addrsize(ip); @@ -1350,8 +1348,8 @@ inetor(PG_FUNCTION_ARGS) } -static Datum -internal_inetpl(inet *ip, int64 plus) +static inet * +internal_inetpl(inet *ip, int64 addend) { inet *dst; @@ -1365,15 +1363,31 @@ internal_inetpl(inet *ip, int64 plus) while (nb-- > 0) { - pdst[nb] = carry = pip[nb] + plus + carry; - plus /= 0x100; /* process next byte */ - carry /= 0x100; /* remove low byte */ - /* Overflow on high byte? */ - if (nb == 0 && (plus != 0 || carry != 0)) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("result out of range"))); + carry = pip[nb] + (int) (addend & 0xFF) + carry; + pdst[nb] = (unsigned char) (carry & 0xFF); + carry >>= 8; + /* + * We have to be careful about right-shifting addend because + * right-shift isn't portable for negative values, while + * simply dividing by 256 doesn't work (the standard rounding + * is in the wrong direction, besides which there may be machines + * out there that round the wrong way). So, explicitly clear + * the low-order byte to remove any doubt about the correct + * result of the division, and then divide rather than shift. + */ + addend &= ~((int64) 0xFF); + addend /= 0x100; } + /* + * At this point we should have addend and carry both zero if + * original addend was >= 0, or addend -1 and carry 1 if original + * addend was < 0. Anything else means overflow. + */ + if (!((addend == 0 && carry == 0) || + (addend == -1 && carry == 1))) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("result out of range"))); } ip_bits(dst) = ip_bits(ip); @@ -1382,7 +1396,7 @@ internal_inetpl(inet *ip, int64 plus) ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); - PG_RETURN_INET_P(dst); + return dst; } @@ -1390,9 +1404,9 @@ Datum inetpl(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); - int64 plus = PG_GETARG_INT64(1); + int64 addend = PG_GETARG_INT64(1); - return internal_inetpl(ip, plus); + PG_RETURN_INET_P(internal_inetpl(ip, addend)); } @@ -1400,9 +1414,9 @@ Datum inetmi_int8(PG_FUNCTION_ARGS) { inet *ip = PG_GETARG_INET_P(0); - int64 plus = PG_GETARG_INT64(1); + int64 addend = PG_GETARG_INT64(1); - return internal_inetpl(ip, -plus); + PG_RETURN_INET_P(internal_inetpl(ip, -addend)); } @@ -1416,42 +1430,53 @@ inetmi(PG_FUNCTION_ARGS) if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("mismatch in address family (%d) != (%d)", - ip_family(ip), ip_family(ip2)))); + errmsg("cannot subtract inet values of different sizes"))); else { + /* + * We form the difference using the traditional complement, + * increment, and add rule, with the increment part being handled + * by starting the carry off at 1. If you don't think integer + * arithmetic is done in two's complement, too bad. + */ int nb = ip_addrsize(ip); int byte = 0; unsigned char *pip = ip_addr(ip); unsigned char *pip2 = ip_addr(ip2); + int carry = 1; while (nb-- > 0) { - /* - * Error if overflow on last byte. This test is tricky - * because if the subtraction == 128 and res is negative, or - * if subtraction == -128 and res is positive, the result - * would still fit in int64. - */ - if (byte + 1 == sizeof(int64) && - (pip[nb] - pip2[nb] >= 128 + (res < 0) || - pip[nb] - pip2[nb] <= -128 - (res > 0))) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("result out of range"))); - if (byte >= sizeof(int64)) + int lobyte; + + carry = pip[nb] + (~pip2[nb] & 0xFF) + carry; + lobyte = carry & 0xFF; + if (byte < sizeof(int64)) { - /* Error if bytes beyond int64 length differ. */ - if (pip[nb] != pip2[nb]) + res |= ((int64) lobyte) << (byte * 8); + } + else + { + /* + * Input wider than int64: check for overflow. All bytes + * to the left of what will fit should be 0 or 0xFF, + * depending on sign of the now-complete result. + */ + if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result out of range"))); } - else - res += (int64)(pip[nb] - pip2[nb]) << (byte * 8); - + carry >>= 8; byte++; } + + /* + * If input is narrower than int64, overflow is not possible, but + * we have to do proper sign extension. + */ + if (carry == 0 && byte < sizeof(int64)) + res |= ((int64) -1) << (byte * 8); } PG_RETURN_INT64(res); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 0a76b86aee..93e186d5b1 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.395 2006/02/11 03:32:39 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.396 2006/02/11 20:39:58 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2297,7 +2297,7 @@ DESCR("bitwise or"); DATA(insert OID = 1675 ( bitxor PGNSP PGUID 12 f f t f i 2 1560 "1560 1560" _null_ _null_ _null_ bitxor - _null_ )); DESCR("bitwise exclusive or"); DATA(insert OID = 1676 ( bitnot PGNSP PGUID 12 f f t f i 1 1560 "1560" _null_ _null_ _null_ bitnot - _null_ )); -DESCR("bitwise negation"); +DESCR("bitwise not"); DATA(insert OID = 1677 ( bitshiftleft PGNSP PGUID 12 f f t f i 2 1560 "1560 23" _null_ _null_ _null_ bitshiftleft - _null_ )); DESCR("bitwise left shift"); DATA(insert OID = 1678 ( bitshiftright PGNSP PGUID 12 f f t f i 2 1560 "1560 23" _null_ _null_ _null_ bitshiftright - _null_ )); @@ -2423,28 +2423,28 @@ DATA(insert OID = 1715 ( cidr PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _n DESCR("coerce inet to cidr"); DATA(insert OID = 2196 ( inet_client_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_client_addr - _null_ )); -DESCR("INET address of the client"); +DESCR("inet address of the client"); DATA(insert OID = 2197 ( inet_client_port PGNSP PGUID 12 f f f f s 0 23 "" _null_ _null_ _null_ inet_client_port - _null_ )); DESCR("client's port number for this connection"); DATA(insert OID = 2198 ( inet_server_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_server_addr - _null_ )); -DESCR("INET address of the server"); +DESCR("inet address of the server"); DATA(insert OID = 2199 ( inet_server_port PGNSP PGUID 12 f f f f s 0 23 "" _null_ _null_ _null_ inet_server_port - _null_ )); DESCR("server's port number for this connection"); DATA(insert OID = 2627 ( inetnot PGNSP PGUID 12 f f t f i 1 869 "869" _null_ _null_ _null_ inetnot - _null_ )); -DESCR("binary NOT"); +DESCR("bitwise not"); DATA(insert OID = 2628 ( inetand PGNSP PGUID 12 f f t f i 2 869 "869 869" _null_ _null_ _null_ inetand - _null_ )); -DESCR("binary AND"); +DESCR("bitwise and"); DATA(insert OID = 2629 ( inetor PGNSP PGUID 12 f f t f i 2 869 "869 869" _null_ _null_ _null_ inetor - _null_ )); -DESCR("binary OR"); +DESCR("bitwise or"); DATA(insert OID = 2630 ( inetpl PGNSP PGUID 12 f f t f i 2 869 "869 20" _null_ _null_ _null_ inetpl - _null_ )); -DESCR("add integer to INET value"); -DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 f f t f i 2 869 "20 869" _null_ _null_ _null_ "select $2 + $1" - _null_ )); -DESCR("add integer to INET value"); +DESCR("add integer to inet value"); +DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 f f t f i 2 869 "20 869" _null_ _null_ _null_ "select $2 + $1" - _null_ )); +DESCR("add integer to inet value"); DATA(insert OID = 2632 ( inetmi_int8 PGNSP PGUID 12 f f t f i 2 869 "869 20" _null_ _null_ _null_ inetmi_int8 - _null_ )); -DESCR("subtract integer from INET value"); +DESCR("subtract integer from inet value"); DATA(insert OID = 2633 ( inetmi PGNSP PGUID 12 f f t f i 2 20 "869 869" _null_ _null_ _null_ inetmi - _null_ )); -DESCR("subtract INET values"); +DESCR("subtract inet values"); DATA(insert OID = 1686 ( numeric PGNSP PGUID 12 f f t f i 1 1700 "25" _null_ _null_ _null_ text_numeric - _null_ )); DESCR("(internal)"); diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index 6c96f7d71b..52a5a8c89b 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -39,22 +39,22 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL; ten | cidr | inet -----+--------------------+------------------ | 192.168.1.0/24 | 192.168.1.226/24 - | 192.168.1.0/26 | 192.168.1.226 - | 192.168.1.0/24 | 192.168.1.0/24 - | 192.168.1.0/24 | 192.168.1.0/25 + | 192.168.1.0/26 | 192.168.1.226 + | 192.168.1.0/24 | 192.168.1.0/24 + | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/25 - | 10.0.0.0/8 | 10.1.2.3/8 - | 10.0.0.0/32 | 10.1.2.3/8 - | 10.1.2.3/32 | 10.1.2.3 - | 10.1.2.0/24 | 10.1.2.3/24 - | 10.1.0.0/16 | 10.1.2.3/16 - | 10.0.0.0/8 | 10.1.2.3/8 - | 10.0.0.0/8 | 11.1.2.3/8 - | 10.0.0.0/8 | 9.1.2.3/8 - | 10:23::f1/128 | 10:23::f1/64 - | 10:23::8000/113 | 10:23::ffff - | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 + | 10.0.0.0/8 | 10.1.2.3/8 + | 10.0.0.0/32 | 10.1.2.3/8 + | 10.1.2.3/32 | 10.1.2.3 + | 10.1.2.0/24 | 10.1.2.3/24 + | 10.1.0.0/16 | 10.1.2.3/16 + | 10.0.0.0/8 | 10.1.2.3/8 + | 10.0.0.0/8 | 11.1.2.3/8 + | 10.0.0.0/8 | 9.1.2.3/8 + | 10:23::f1/128 | 10:23::f1/64 + | 10:23::8000/113 | 10:23::ffff + | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 (17 rows) -- now test some support functions @@ -84,22 +84,22 @@ SELECT '' AS ten, c AS cidr, broadcast(c), i AS inet, broadcast(i) FROM INET_TBL; ten | cidr | broadcast | inet | broadcast -----+--------------------+------------------+------------------+--------------------------------------- - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24 - | 192.168.1.0/26 | 192.168.1.63/26 | 192.168.1.226 | 192.168.1.226 - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24 - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25 - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24 - | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25 - | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 - | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8 - | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3 - | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24 - | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16 - | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 - | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8 - | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8 - | 10:23::f1/128 | 10:23::f1 | 10:23::f1/64 | 10:23::ffff:ffff:ffff:ffff/64 - | 10:23::8000/113 | 10:23::ffff/113 | 10:23::ffff | 10:23::ffff + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24 + | 192.168.1.0/26 | 192.168.1.63/26 | 192.168.1.226 | 192.168.1.226 + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24 + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/25 | 192.168.1.127/25 + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 | 192.168.1.255/24 + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/25 | 192.168.1.255/25 + | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 + | 10.0.0.0/32 | 10.0.0.0 | 10.1.2.3/8 | 10.255.255.255/8 + | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3 | 10.1.2.3 + | 10.1.2.0/24 | 10.1.2.255/24 | 10.1.2.3/24 | 10.1.2.255/24 + | 10.1.0.0/16 | 10.1.255.255/16 | 10.1.2.3/16 | 10.1.255.255/16 + | 10.0.0.0/8 | 10.255.255.255/8 | 10.1.2.3/8 | 10.255.255.255/8 + | 10.0.0.0/8 | 10.255.255.255/8 | 11.1.2.3/8 | 11.255.255.255/8 + | 10.0.0.0/8 | 10.255.255.255/8 | 9.1.2.3/8 | 9.255.255.255/8 + | 10:23::f1/128 | 10:23::f1 | 10:23::f1/64 | 10:23::ffff:ffff:ffff:ffff/64 + | 10:23::8000/113 | 10:23::ffff/113 | 10:23::ffff | 10:23::ffff | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4 | ::4.3.2.1/24 | 0:ff:ffff:ffff:ffff:ffff:ffff:ffff/24 (17 rows) @@ -107,23 +107,23 @@ SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)", i AS inet, network(i) AS "network(inet)" FROM INET_TBL; ten | cidr | network(cidr) | inet | network(inet) -----+--------------------+--------------------+------------------+------------------ - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24 + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.226/24 | 192.168.1.0/24 | 192.168.1.0/26 | 192.168.1.0/26 | 192.168.1.226 | 192.168.1.226/32 - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25 - | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/25 | 192.168.1.0/25 + | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.255/25 | 192.168.1.128/25 - | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 - | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8 - | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32 - | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24 - | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16 - | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 - | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8 - | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8 - | 10:23::f1/128 | 10:23::f1/128 | 10:23::f1/64 | 10:23::/64 - | 10:23::8000/113 | 10:23::8000/113 | 10:23::ffff | 10:23::ffff/128 - | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 | ::/24 + | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 + | 10.0.0.0/32 | 10.0.0.0/32 | 10.1.2.3/8 | 10.0.0.0/8 + | 10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3 | 10.1.2.3/32 + | 10.1.2.0/24 | 10.1.2.0/24 | 10.1.2.3/24 | 10.1.2.0/24 + | 10.1.0.0/16 | 10.1.0.0/16 | 10.1.2.3/16 | 10.1.0.0/16 + | 10.0.0.0/8 | 10.0.0.0/8 | 10.1.2.3/8 | 10.0.0.0/8 + | 10.0.0.0/8 | 10.0.0.0/8 | 11.1.2.3/8 | 11.0.0.0/8 + | 10.0.0.0/8 | 10.0.0.0/8 | 9.1.2.3/8 | 9.0.0.0/8 + | 10:23::f1/128 | 10:23::f1/128 | 10:23::f1/64 | 10:23::/64 + | 10:23::8000/113 | 10:23::8000/113 | 10:23::ffff | 10:23::ffff/128 + | ::ffff:1.2.3.4/128 | ::ffff:1.2.3.4/128 | ::4.3.2.1/24 | ::/24 (17 rows) SELECT '' AS ten, c AS cidr, masklen(c) AS "masklen(cidr)", @@ -165,7 +165,7 @@ SELECT '' AS six, c AS cidr, i AS inet FROM INET_TBL six | cidr | inet -----+----------------+---------------- | 192.168.1.0/24 | 192.168.1.0/24 - | 10.1.2.3/32 | 10.1.2.3 + | 10.1.2.3/32 | 10.1.2.3 (2 rows) SELECT '' AS ten, i, c, @@ -176,23 +176,23 @@ SELECT '' AS ten, i, c, FROM INET_TBL; ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe -----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+----- - | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t - | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f - | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t - | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f - | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t - | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t - | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t - | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t - | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t - | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f - | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f - | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t - | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f - | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t + | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t + | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f + | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t + | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f + | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t + | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t + | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t + | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t + | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t + | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t + | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f + | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f + | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t + | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f + | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t (17 rows) -- check the conversion to/from text and set_netmask @@ -201,21 +201,21 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL; -----+------------------ | 192.168.1.226/24 | 192.168.1.226/24 - | 192.168.1.0/24 - | 192.168.1.0/24 + | 192.168.1.0/24 + | 192.168.1.0/24 | 192.168.1.255/24 | 192.168.1.255/24 - | 10.1.2.3/24 - | 10.1.2.3/24 - | 10.1.2.3/24 - | 10.1.2.3/24 - | 10.1.2.3/24 - | 10.1.2.3/24 - | 11.1.2.3/24 - | 9.1.2.3/24 - | 10:23::f1/24 - | 10:23::ffff/24 - | ::4.3.2.1/24 + | 10.1.2.3/24 + | 10.1.2.3/24 + | 10.1.2.3/24 + | 10.1.2.3/24 + | 10.1.2.3/24 + | 10.1.2.3/24 + | 11.1.2.3/24 + | 9.1.2.3/24 + | 10:23::f1/24 + | 10:23::ffff/24 + | ::4.3.2.1/24 (17 rows) -- check that index works correctly @@ -224,153 +224,224 @@ SET enable_seqscan TO off; SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; c | i ----------------+------------------ - 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.0/25 192.168.1.0/24 | 192.168.1.255/25 - 192.168.1.0/26 | 192.168.1.226 + 192.168.1.0/26 | 192.168.1.226 (3 rows) SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; c | i ----------------+------------------ - 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/24 | 192.168.1.0/24 192.168.1.0/24 | 192.168.1.226/24 192.168.1.0/24 | 192.168.1.255/24 - 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.0/24 | 192.168.1.0/25 192.168.1.0/24 | 192.168.1.255/25 - 192.168.1.0/26 | 192.168.1.226 + 192.168.1.0/26 | 192.168.1.226 (6 rows) -SELECT ~i FROM inet_tbl; - ?column? --------------------------------------------- - 63.87.254.29/24 - 63.87.254.29 - 63.87.254.255/24 - 63.87.254.255/25 - 63.87.254.0/24 - 63.87.254.0/25 - 245.254.253.252/8 - 245.254.253.252/8 - 245.254.253.252 - 245.254.253.252/24 - 245.254.253.252/16 - 245.254.253.252/8 - 244.254.253.252/8 - 246.254.253.252/8 - ffef:ffdc:ffff:ffff:ffff:ffff:ffff:ff0e/64 - ffef:ffdc:ffff:ffff:ffff:ffff:ffff:0 - ffff:ffff:ffff:ffff:ffff:ffff:fbfc:fdfe/24 -(17 rows) - -SELECT i & c FROM inet_tbl; - ?column? ----------------- - 192.168.1.0/24 - 192.168.1.0 - 192.168.1.0/24 - 192.168.1.0/25 - 192.168.1.0/24 - 192.168.1.0/25 - 10.0.0.0/8 - 10.0.0.0 - 10.1.2.3 - 10.1.2.0/24 - 10.1.0.0/16 - 10.0.0.0/8 - 10.0.0.0/8 - 8.0.0.0/8 - 10:23::f1 - 10:23::8000 - ::0.2.2.0 -(17 rows) - -SELECT i | c FROM inet_tbl; - ?column? ------------------- - 192.168.1.226/24 - 192.168.1.226 - 192.168.1.0/24 - 192.168.1.0/25 - 192.168.1.255/24 - 192.168.1.255/25 - 10.1.2.3/8 - 10.1.2.3 - 10.1.2.3 - 10.1.2.3/24 - 10.1.2.3/16 - 10.1.2.3/8 - 11.1.2.3/8 - 11.1.2.3/8 - 10:23::f1 - 10:23::ffff - ::ffff:5.3.3.5 -(17 rows) - -SELECT i + 500 FROM inet_tbl; - ?column? ------------------- - 192.168.4.214/24 - 192.168.4.214 - 192.168.3.244/24 - 192.168.3.244/25 - 192.168.4.243/24 - 192.168.4.243/25 - 10.1.4.247/8 - 10.1.4.247/8 - 10.1.4.247 - 10.1.4.247/24 - 10.1.4.247/16 - 10.1.4.247/8 - 11.1.4.247/8 - 9.1.4.247/8 - 10:23::3e5/64 - 10:23::1:2f3 - ::4.3.4.245/24 -(17 rows) - -SELECT i - 500 FROM inet_tbl; - ?column? --------------------- - 192.168.255.238/24 - 192.168.255.238 - 192.168.255.12/24 - 192.168.255.12/25 - 192.168.0.11/24 - 192.168.0.11/25 - 10.1.0.15/8 - 10.1.0.15/8 - 10.1.0.15 - 10.1.0.15/24 - 10.1.0.15/16 - 10.1.0.15/8 - 11.1.0.15/8 - 9.1.0.15/8 - 10:23::fefd/64 - 10:23::fe0b - ::4.3.0.13/24 -(17 rows) - -SELECT i - c FROM inet_tbl; - ?column? ------------------- - 226 - 226 - 0 - 0 - 255 - 255 - 66051 - 66051 - 0 - 3 - 515 - 66051 - 16843267 - -16711165 - 0 - 32767 - -281470631346435 -(17 rows) - SET enable_seqscan TO on; DROP INDEX inet_idx1; +-- simple tests of inet boolean and arithmetic operators +SELECT i, ~i AS "~i" FROM inet_tbl; + i | ~i +------------------+-------------------------------------------- + 192.168.1.226/24 | 63.87.254.29/24 + 192.168.1.226 | 63.87.254.29 + 192.168.1.0/24 | 63.87.254.255/24 + 192.168.1.0/25 | 63.87.254.255/25 + 192.168.1.255/24 | 63.87.254.0/24 + 192.168.1.255/25 | 63.87.254.0/25 + 10.1.2.3/8 | 245.254.253.252/8 + 10.1.2.3/8 | 245.254.253.252/8 + 10.1.2.3 | 245.254.253.252 + 10.1.2.3/24 | 245.254.253.252/24 + 10.1.2.3/16 | 245.254.253.252/16 + 10.1.2.3/8 | 245.254.253.252/8 + 11.1.2.3/8 | 244.254.253.252/8 + 9.1.2.3/8 | 246.254.253.252/8 + 10:23::f1/64 | ffef:ffdc:ffff:ffff:ffff:ffff:ffff:ff0e/64 + 10:23::ffff | ffef:ffdc:ffff:ffff:ffff:ffff:ffff:0 + ::4.3.2.1/24 | ffff:ffff:ffff:ffff:ffff:ffff:fbfc:fdfe/24 +(17 rows) + +SELECT i, c, i & c AS "and" FROM inet_tbl; + i | c | and +------------------+--------------------+---------------- + 192.168.1.226/24 | 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.226 | 192.168.1.0/26 | 192.168.1.0 + 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/25 | 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.255/25 | 192.168.1.0/24 | 192.168.1.0/25 + 10.1.2.3/8 | 10.0.0.0/8 | 10.0.0.0/8 + 10.1.2.3/8 | 10.0.0.0/32 | 10.0.0.0 + 10.1.2.3 | 10.1.2.3/32 | 10.1.2.3 + 10.1.2.3/24 | 10.1.2.0/24 | 10.1.2.0/24 + 10.1.2.3/16 | 10.1.0.0/16 | 10.1.0.0/16 + 10.1.2.3/8 | 10.0.0.0/8 | 10.0.0.0/8 + 11.1.2.3/8 | 10.0.0.0/8 | 10.0.0.0/8 + 9.1.2.3/8 | 10.0.0.0/8 | 8.0.0.0/8 + 10:23::f1/64 | 10:23::f1/128 | 10:23::f1 + 10:23::ffff | 10:23::8000/113 | 10:23::8000 + ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | ::0.2.2.0 +(17 rows) + +SELECT i, c, i | c AS "or" FROM inet_tbl; + i | c | or +------------------+--------------------+------------------ + 192.168.1.226/24 | 192.168.1.0/24 | 192.168.1.226/24 + 192.168.1.226 | 192.168.1.0/26 | 192.168.1.226 + 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/25 | 192.168.1.0/24 | 192.168.1.0/25 + 192.168.1.255/24 | 192.168.1.0/24 | 192.168.1.255/24 + 192.168.1.255/25 | 192.168.1.0/24 | 192.168.1.255/25 + 10.1.2.3/8 | 10.0.0.0/8 | 10.1.2.3/8 + 10.1.2.3/8 | 10.0.0.0/32 | 10.1.2.3 + 10.1.2.3 | 10.1.2.3/32 | 10.1.2.3 + 10.1.2.3/24 | 10.1.2.0/24 | 10.1.2.3/24 + 10.1.2.3/16 | 10.1.0.0/16 | 10.1.2.3/16 + 10.1.2.3/8 | 10.0.0.0/8 | 10.1.2.3/8 + 11.1.2.3/8 | 10.0.0.0/8 | 11.1.2.3/8 + 9.1.2.3/8 | 10.0.0.0/8 | 11.1.2.3/8 + 10:23::f1/64 | 10:23::f1/128 | 10:23::f1 + 10:23::ffff | 10:23::8000/113 | 10:23::ffff + ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | ::ffff:5.3.3.5 +(17 rows) + +SELECT i, i + 500 AS "i+500" FROM inet_tbl; + i | i+500 +------------------+------------------ + 192.168.1.226/24 | 192.168.3.214/24 + 192.168.1.226 | 192.168.3.214 + 192.168.1.0/24 | 192.168.2.244/24 + 192.168.1.0/25 | 192.168.2.244/25 + 192.168.1.255/24 | 192.168.3.243/24 + 192.168.1.255/25 | 192.168.3.243/25 + 10.1.2.3/8 | 10.1.3.247/8 + 10.1.2.3/8 | 10.1.3.247/8 + 10.1.2.3 | 10.1.3.247 + 10.1.2.3/24 | 10.1.3.247/24 + 10.1.2.3/16 | 10.1.3.247/16 + 10.1.2.3/8 | 10.1.3.247/8 + 11.1.2.3/8 | 11.1.3.247/8 + 9.1.2.3/8 | 9.1.3.247/8 + 10:23::f1/64 | 10:23::2e5/64 + 10:23::ffff | 10:23::1:1f3 + ::4.3.2.1/24 | ::4.3.3.245/24 +(17 rows) + +SELECT i, i - 500 AS "i-500" FROM inet_tbl; + i | i-500 +------------------+---------------------------------------- + 192.168.1.226/24 | 192.167.255.238/24 + 192.168.1.226 | 192.167.255.238 + 192.168.1.0/24 | 192.167.255.12/24 + 192.168.1.0/25 | 192.167.255.12/25 + 192.168.1.255/24 | 192.168.0.11/24 + 192.168.1.255/25 | 192.168.0.11/25 + 10.1.2.3/8 | 10.1.0.15/8 + 10.1.2.3/8 | 10.1.0.15/8 + 10.1.2.3 | 10.1.0.15 + 10.1.2.3/24 | 10.1.0.15/24 + 10.1.2.3/16 | 10.1.0.15/16 + 10.1.2.3/8 | 10.1.0.15/8 + 11.1.2.3/8 | 11.1.0.15/8 + 9.1.2.3/8 | 9.1.0.15/8 + 10:23::f1/64 | 10:22:ffff:ffff:ffff:ffff:ffff:fefd/64 + 10:23::ffff | 10:23::fe0b + ::4.3.2.1/24 | ::4.3.0.13/24 +(17 rows) + +SELECT i, c, i - c AS "minus" FROM inet_tbl; + i | c | minus +------------------+--------------------+------------------ + 192.168.1.226/24 | 192.168.1.0/24 | 226 + 192.168.1.226 | 192.168.1.0/26 | 226 + 192.168.1.0/24 | 192.168.1.0/24 | 0 + 192.168.1.0/25 | 192.168.1.0/24 | 0 + 192.168.1.255/24 | 192.168.1.0/24 | 255 + 192.168.1.255/25 | 192.168.1.0/24 | 255 + 10.1.2.3/8 | 10.0.0.0/8 | 66051 + 10.1.2.3/8 | 10.0.0.0/32 | 66051 + 10.1.2.3 | 10.1.2.3/32 | 0 + 10.1.2.3/24 | 10.1.2.0/24 | 3 + 10.1.2.3/16 | 10.1.0.0/16 | 515 + 10.1.2.3/8 | 10.0.0.0/8 | 66051 + 11.1.2.3/8 | 10.0.0.0/8 | 16843267 + 9.1.2.3/8 | 10.0.0.0/8 | -16711165 + 10:23::f1/64 | 10:23::f1/128 | 0 + 10:23::ffff | 10:23::8000/113 | 32767 + ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | -281470631346435 +(17 rows) + +SELECT '127.0.0.1'::inet + 257; + ?column? +----------- + 127.0.1.2 +(1 row) + +SELECT ('127.0.0.1'::inet + 257) - 257; + ?column? +----------- + 127.0.0.1 +(1 row) + +SELECT '127::1'::inet + 257; + ?column? +---------- + 127::102 +(1 row) + +SELECT ('127::1'::inet + 257) - 257; + ?column? +---------- + 127::1 +(1 row) + +SELECT '127.0.0.2'::inet - ('127.0.0.2'::inet + 500); + ?column? +---------- + -500 +(1 row) + +SELECT '127.0.0.2'::inet - ('127.0.0.2'::inet - 500); + ?column? +---------- + 500 +(1 row) + +SELECT '127::2'::inet - ('127::2'::inet + 500); + ?column? +---------- + -500 +(1 row) + +SELECT '127::2'::inet - ('127::2'::inet - 500); + ?column? +---------- + 500 +(1 row) + +-- these should give overflow errors: +SELECT '127.0.0.1'::inet + 10000000000; +ERROR: result out of range +SELECT '127.0.0.1'::inet - 10000000000; +ERROR: result out of range +SELECT '126::1'::inet - '127::2'::inet; +ERROR: result out of range +SELECT '127::1'::inet - '126::2'::inet; +ERROR: result out of range +-- but not these +SELECT '127::1'::inet + 10000000000; + ?column? +------------------ + 127::2:540b:e401 +(1 row) + +SELECT '127::1'::inet - '127::2'::inet; + ?column? +---------- + -1 +(1 row) + diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index f44caf5006..f88a17eabc 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -62,14 +62,29 @@ CREATE INDEX inet_idx1 ON inet_tbl(i); SET enable_seqscan TO off; SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr; SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr; - -SELECT ~i FROM inet_tbl; -SELECT i & c FROM inet_tbl; -SELECT i | c FROM inet_tbl; -SELECT i + 500 FROM inet_tbl; -SELECT i - 500 FROM inet_tbl; -SELECT i - c FROM inet_tbl; - SET enable_seqscan TO on; DROP INDEX inet_idx1; +-- simple tests of inet boolean and arithmetic operators +SELECT i, ~i AS "~i" FROM inet_tbl; +SELECT i, c, i & c AS "and" FROM inet_tbl; +SELECT i, c, i | c AS "or" FROM inet_tbl; +SELECT i, i + 500 AS "i+500" FROM inet_tbl; +SELECT i, i - 500 AS "i-500" FROM inet_tbl; +SELECT i, c, i - c AS "minus" FROM inet_tbl; +SELECT '127.0.0.1'::inet + 257; +SELECT ('127.0.0.1'::inet + 257) - 257; +SELECT '127::1'::inet + 257; +SELECT ('127::1'::inet + 257) - 257; +SELECT '127.0.0.2'::inet - ('127.0.0.2'::inet + 500); +SELECT '127.0.0.2'::inet - ('127.0.0.2'::inet - 500); +SELECT '127::2'::inet - ('127::2'::inet + 500); +SELECT '127::2'::inet - ('127::2'::inet - 500); +-- these should give overflow errors: +SELECT '127.0.0.1'::inet + 10000000000; +SELECT '127.0.0.1'::inet - 10000000000; +SELECT '126::1'::inet - '127::2'::inet; +SELECT '127::1'::inet - '126::2'::inet; +-- but not these +SELECT '127::1'::inet + 10000000000; +SELECT '127::1'::inet - '127::2'::inet;