]> granicus.if.org Git - postgresql/commitdiff
Add INET/CIDR operators: and, or, not, plus int8, minus int8, and inet
authorBruce Momjian <bruce@momjian.us>
Sat, 11 Feb 2006 03:32:41 +0000 (03:32 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 11 Feb 2006 03:32:41 +0000 (03:32 +0000)
minus inet.

Stephen R. van den Berg

doc/src/sgml/func.sgml
src/backend/utils/adt/network.c
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/inet.out
src/test/regress/sql/inet.sql

index 8f6f1ba392609e633cf555fa0a3070f627e4870a..e2c27e1a35ae5b15ee57bd5a8a57d6e71d32d915 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.303 2006/01/26 02:35:48 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.304 2006/02/11 03:32:38 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -6787,6 +6787,36 @@ SELECT pg_sleep(1.5);
         <entry>contains or equals</entry>
         <entry><literal>inet '192.168.1/24' &gt;&gt;= inet '192.168.1/24'</literal></entry>
        </row>
+       <row>
+        <entry> <literal>~</literal> </entry>
+        <entry>bitwise NOT</entry>
+        <entry><literal>~ inet '192.168.1.6'</literal></entry>
+       </row>
+       <row>
+        <entry> <literal>&amp;</literal> </entry>
+        <entry>bitwise AND</entry>
+        <entry><literal>inet '192.168.1.6' &amp; inet '0.0.0.255'</literal></entry>
+       </row>
+       <row>
+        <entry> <literal>|</literal> </entry>
+        <entry>bitwise OR</entry>
+        <entry><literal>inet '192.168.1.6' | inet '0.0.0.255'</literal></entry>
+       </row>
+       <row>
+        <entry> <literal>+</literal> </entry>
+        <entry>addition</entry>
+        <entry><literal>inet '192.168.1.6' + 25</literal></entry>
+       </row>
+       <row>
+        <entry> <literal>-</literal> </entry>
+        <entry>subtraction</entry>
+        <entry><literal>inet '192.168.1.43' - 36</literal></entry>
+       </row>
+       <row>
+        <entry> <literal>-</literal> </entry>
+        <entry>subtraction</entry>
+        <entry><literal>inet '192.168.1.43' - inet '192.168.1.19'</literal></entry>
+       </row>
       </tbody>
      </tgroup>
     </table>
index c7ce7b6a307346eefc6875401c47f32cf0656347..64daefa02949e52f33f1a8298b94d554543442b1 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.63 2006/02/07 17:04:04 momjian Exp $
+ *     $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/11 03:32:39 momjian Exp $
  *
  *     Jon Postel RIP 16 Oct 1998
  */
@@ -27,6 +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);
 
 /*
  *     Access macros.
@@ -1250,3 +1251,208 @@ inet_server_port(PG_FUNCTION_ARGS)
 
        PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port)));
 }
+
+
+Datum
+inetnot(PG_FUNCTION_ARGS)
+{
+       inet       *ip = PG_GETARG_INET_P(0);
+       inet       *dst;
+
+       dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
+
+       {
+               int nb = ip_addrsize(ip);
+               unsigned char   *pip = ip_addr(ip);
+               unsigned char   *pdst = ip_addr(dst);
+
+               while (nb-- > 0)
+                       pdst[nb] = ~pip[nb];
+       }
+       ip_bits(dst) = ip_bits(ip);
+
+       ip_family(dst) = ip_family(ip);
+       VARATT_SIZEP(dst) = VARHDRSZ +
+               ((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
+               ip_addrsize(dst);
+
+       PG_RETURN_INET_P(dst);
+}
+
+
+Datum
+inetand(PG_FUNCTION_ARGS)
+{
+       inet       *ip = PG_GETARG_INET_P(0);
+       inet       *ip2 = PG_GETARG_INET_P(1);
+       inet       *dst;
+
+       dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
+
+       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))));
+       else
+       {
+               int nb = ip_addrsize(ip);
+               unsigned char   *pip = ip_addr(ip);
+               unsigned char   *pip2 = ip_addr(ip2);
+               unsigned char   *pdst = ip_addr(dst);
+
+               while (nb-- > 0)
+                       pdst[nb] = pip[nb] & pip2[nb];
+       }
+       ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
+
+       ip_family(dst) = ip_family(ip);
+       VARATT_SIZEP(dst) = VARHDRSZ +
+               ((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
+               ip_addrsize(dst);
+
+       PG_RETURN_INET_P(dst);
+}
+
+
+Datum
+inetor(PG_FUNCTION_ARGS)
+{
+       inet       *ip = PG_GETARG_INET_P(0);
+       inet       *ip2 = PG_GETARG_INET_P(1);
+       inet       *dst;
+
+       dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
+
+       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))));
+       else
+       {
+               int nb = ip_addrsize(ip);
+               unsigned char   *pip = ip_addr(ip);
+               unsigned char   *pip2 = ip_addr(ip2);
+               unsigned char   *pdst = ip_addr(dst);
+
+               while (nb-- > 0)
+                       pdst[nb] = pip[nb] | pip2[nb];
+       }
+       ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
+
+       ip_family(dst) = ip_family(ip);
+       VARATT_SIZEP(dst) = VARHDRSZ +
+               ((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
+               ip_addrsize(dst);
+
+       PG_RETURN_INET_P(dst);
+}
+
+
+static Datum
+internal_inetpl(inet *ip, int64 plus)
+{
+       inet       *dst;
+
+       dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
+
+       {
+               int nb = ip_addrsize(ip);
+               unsigned char   *pip = ip_addr(ip);
+               unsigned char   *pdst = ip_addr(dst);
+               int carry = 0;
+
+               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")));
+               }
+       }
+       ip_bits(dst) = ip_bits(ip);
+
+       ip_family(dst) = ip_family(ip);
+       VARATT_SIZEP(dst) = VARHDRSZ +
+               ((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
+               ip_addrsize(dst);
+
+       PG_RETURN_INET_P(dst);
+}
+
+
+Datum
+inetpl(PG_FUNCTION_ARGS)
+{
+       inet   *ip = PG_GETARG_INET_P(0);
+       int64   plus = PG_GETARG_INT64(1);
+
+       return internal_inetpl(ip, plus);
+}
+
+
+Datum
+inetmi_int8(PG_FUNCTION_ARGS)
+{
+       inet   *ip = PG_GETARG_INET_P(0);
+       int64   plus = PG_GETARG_INT64(1);
+
+       return internal_inetpl(ip, -plus);
+}
+
+
+Datum
+inetmi(PG_FUNCTION_ARGS)
+{
+       inet       *ip = PG_GETARG_INET_P(0);
+       inet       *ip2 = PG_GETARG_INET_P(1);
+       int64           res = 0;
+
+       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))));
+       else
+       {
+               int nb = ip_addrsize(ip);
+               int     byte = 0;
+               unsigned char   *pip = ip_addr(ip);
+               unsigned char   *pip2 = ip_addr(ip2);
+
+               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))
+                       {
+                               /* Error if bytes beyond int64 length differ. */
+                               if (pip[nb] != pip2[nb])
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+                                                        errmsg("result out of range")));
+                       }
+                       else
+                               res += (int64)(pip[nb] - pip2[nb]) << (byte * 8);
+
+                       byte++;
+               }
+       }
+
+       PG_RETURN_INT64(res);
+}
index 9b426f6c5951b008e15b32b9e228ed231968f3ca..72625937c321e3f14116ee167b97d901392e4596 100644 (file)
@@ -8,7 +8,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_operator.h,v 1.138 2006/01/26 02:35:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.139 2006/02/11 03:32:39 momjian Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -653,6 +653,15 @@ DATA(insert OID = 933  (  ">>"        PGNSP PGUID b f 869 869       16 931         0        0        0   0
 DATA(insert OID = 934  (  ">>="    PGNSP PGUID b f 869 869      16 932         0        0        0   0   0 network_supeq - - ));
 #define OID_INET_SUPEQ_OP                              934
 
+DATA(insert OID = 2634 (  "~"     PGNSP PGUID l f      0 869 869 0 0 0 0 0 0 inetnot - - ));
+DATA(insert OID = 2635 (  "&"     PGNSP PGUID b f      869 869 869 0 0 0 0 0 0 inetand - - ));
+DATA(insert OID = 2636 (  "|"     PGNSP PGUID b f      869 869 869 0 0 0 0 0 0 inetor - - ));
+DATA(insert OID = 2637 (  "+"     PGNSP PGUID b f      869 20 869 2638 0 0 0 0 0 inetpl - - ));
+DATA(insert OID = 2638 (  "+"     PGNSP PGUID b f      20 869 869 2637 0 0 0 0 0 int8pl_inet - - ));
+DATA(insert OID = 2639 (  "-"     PGNSP PGUID b f      869 20 869 0 0 0 0 0 0 inetmi_int8 - - ));
+DATA(insert OID = 2640 (  "-"     PGNSP PGUID b f      869 869 20 0 0 0 0 0 0 inetmi - - ));
+
+
 /* case-insensitive LIKE hacks */
 DATA(insert OID = 1625 (  "~~*"   PGNSP PGUID b f  19  25      16 0 1626 0 0 0 0 nameiclike iclikesel iclikejoinsel ));
 #define OID_NAME_ICLIKE_OP             1625
index 6df857b5514df769cfc7db064d5abcdcba867f79..0a76b86aee32a4eb57b6d0ac4885dd89791c9ad1 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.394 2006/02/09 14:53:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.395 2006/02/11 03:32:39 momjian Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2431,6 +2431,21 @@ 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");
+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");
+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");
+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");
+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");
+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");
+
 DATA(insert OID = 1686 ( numeric                       PGNSP PGUID 12 f f t f i 1 1700 "25" _null_ _null_ _null_ text_numeric - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1688 ( text                          PGNSP PGUID 12 f f t f i 1 25 "1700" _null_ _null_ _null_ numeric_text - _null_ ));
index 527d5ce8e88d7c98e08b0a671f34a9677530fb59..d79749a8a4f74a51d92a60bf504b38213a604f95 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/utils/builtins.h,v 1.272 2006/01/26 02:35:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.273 2006/02/11 03:32:41 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -734,6 +734,12 @@ extern Datum inet_client_addr(PG_FUNCTION_ARGS);
 extern Datum inet_client_port(PG_FUNCTION_ARGS);
 extern Datum inet_server_addr(PG_FUNCTION_ARGS);
 extern Datum inet_server_port(PG_FUNCTION_ARGS);
+extern Datum inetnot(PG_FUNCTION_ARGS);
+extern Datum inetand(PG_FUNCTION_ARGS);
+extern Datum inetor(PG_FUNCTION_ARGS);
+extern Datum inetpl(PG_FUNCTION_ARGS);
+extern Datum inetmi_int8(PG_FUNCTION_ARGS);
+extern Datum inetmi(PG_FUNCTION_ARGS);
 
 /* mac.c */
 extern Datum macaddr_in(PG_FUNCTION_ARGS);
index ddcdbba45669ec2f14e8187ea1f1a2daa6ff6727..6c96f7d71b367baf143d6c85a1c8e828f4c86cd5 100644 (file)
@@ -240,5 +240,137 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
  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;
index 46a49006cf557c2db51a7ffd16143bd08085053a..f44caf5006b4feb37aacc8bcf134773c24399344 100644 (file)
@@ -62,6 +62,14 @@ 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;