Fix incorrect addition, subtraction, and overflow checking in new
authorTom Lane
Sat, 11 Feb 2006 20:39:59 +0000 (20:39 +0000)
committerTom Lane
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;