]> granicus.if.org Git - postgresql/commitdiff
Fix incorrect addition, subtraction, and overflow checking in new
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Feb 2006 20:39:59 +0000 (20:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Feb 2006 20:39:59 +0000 (20:39 +0000)
inet operators.

src/backend/utils/adt/network.c
src/include/catalog/pg_proc.h
src/test/regress/expected/inet.out
src/test/regress/sql/inet.sql

index 64daefa02949e52f33f1a8298b94d554543442b1..2624c203f7c46c44fe093596d4aeca6158dafda0 100644 (file)
@@ -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);
index 0a76b86aee32a4eb57b6d0ac4885dd89791c9ad1..93e186d5b12c811d05ba5cba054d1a5f1bf9c9de 100644 (file)
@@ -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)");
index 6c96f7d71b367baf143d6c85a1c8e828f4c86cd5..52a5a8c89bd86d44aa18050bf2c17c1ef2f177f2 100644 (file)
@@ -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
+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 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
+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 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
+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 + 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  
+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 - 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     
+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 FROM inet_tbl;
+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?     
 ------------------
-       226
-       226
-         0
-         0
-       255
-       255
-     66051
-     66051
-         0
-         3
-       515
-     66051
-  16843267
- -16711165
-                0
-            32767
- -281470631346435
-(17 rows)
+ 127::2:540b:e401
+(1 row)
+
+SELECT '127::1'::inet - '127::2'::inet;
+ ?column? 
+----------
+       -1
+(1 row)
 
-SET enable_seqscan TO on;
-DROP INDEX inet_idx1;
index f44caf5006b4feb37aacc8bcf134773c24399344..f88a17eabc7814835cd2df458fc908c5355a1dfa 100644 (file)
@@ -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;