diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 8f6f1ba392609e633cf555fa0a3070f627e4870a..e2c27e1a35ae5b15ee57bd5a8a57d6e71d32d915 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -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' >>= 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>&</literal> </entry> + <entry>bitwise AND</entry> + <entry><literal>inet '192.168.1.6' & 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> diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index c7ce7b6a307346eefc6875401c47f32cf0656347..64daefa02949e52f33f1a8298b94d554543442b1 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for the INET and CIDR types. * - * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.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); +} diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 9b426f6c5951b008e15b32b9e228ed231968f3ca..72625937c321e3f14116ee167b97d901392e4596 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -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 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 6df857b5514df769cfc7db064d5abcdcba867f79..0a76b86aee32a4eb57b6d0ac4885dd89791c9ad1 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.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_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 527d5ce8e88d7c98e08b0a671f34a9677530fb59..d79749a8a4f74a51d92a60bf504b38213a604f95 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/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); diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out index ddcdbba45669ec2f14e8187ea1f1a2daa6ff6727..6c96f7d71b367baf143d6c85a1c8e828f4c86cd5 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -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; diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index 46a49006cf557c2db51a7ffd16143bd08085053a..f44caf5006b4feb37aacc8bcf134773c24399344 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -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;