diff -cr cvs/pgsql/src/backend/utils/adt/network.c cvs.build/pgsql/src/backend/utils/adt/network.c *** cvs/pgsql/src/backend/utils/adt/network.c 2006-01-23 23:52:36.000000000 +0100 --- cvs.build/pgsql/src/backend/utils/adt/network.c 2006-01-24 09:53:37.000000000 +0100 *************** *** 325,330 **** --- 325,387 ---- PG_RETURN_INET_P(dst); } + Datum + inettocidr(PG_FUNCTION_ARGS) + { + inet *src = PG_GETARG_INET_P(0); + inet *dst; + int byte; + int nbits; + int maxbits; + int maxbytes; + unsigned char mask; + + /* make sure any unused bits are zeroed */ + dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + + if (ip_family(src) == PGSQL_AF_INET) + { + maxbits = 32; + maxbytes = 4; + } + else + { + maxbits = 128; + maxbytes = 16; + } + Assert(ip_bits(dst) <= maxbits); + + /* copy over */ + ip_family(dst) = ip_family(src); + ip_bits(dst) = ip_bits(src); + ip_is_cidr(dst) = 1; /* 1 represents CIDR */ + memcpy(ip_addr(dst), ip_addr(src), maxbytes); + + /* zero out the bits that are covered by the netmask */ + if (ip_bits(dst) < maxbits) + { + byte = ip_bits(dst) / 8; + nbits = ip_bits(dst) % 8; + /* reset the first byte, this might be a partial byte */ + mask = 0xff; + if (ip_bits(dst) != 0) + { + mask >>= nbits; + ip_addr(dst)[byte] &= ~mask; + byte++; + } + + /* from now on we reset only complete bytes */ + while (byte < maxbytes) + { + ip_addr(dst)[byte] = 0; + byte++; + } + } + + PG_RETURN_INET_P(dst); + } + /* * Basic comparison function for sorting and inet/cidr comparisons. * diff -cr cvs/pgsql/src/include/catalog/pg_cast.h cvs.build/pgsql/src/include/catalog/pg_cast.h *** cvs/pgsql/src/include/catalog/pg_cast.h 2005-10-21 17:45:06.000000000 +0200 --- cvs.build/pgsql/src/include/catalog/pg_cast.h 2006-01-24 09:38:15.000000000 +0100 *************** *** 249,255 **** * INET category */ DATA(insert ( 650 869 0 i )); ! DATA(insert ( 869 650 0 i )); /* * BitString category --- 249,255 ---- * INET category */ DATA(insert ( 650 869 0 i )); ! DATA(insert ( 869 650 1265 a )); /* * BitString category diff -cr cvs/pgsql/src/include/catalog/pg_proc.h cvs.build/pgsql/src/include/catalog/pg_proc.h *** cvs/pgsql/src/include/catalog/pg_proc.h 2006-01-20 13:52:12.000000000 +0100 --- cvs.build/pgsql/src/include/catalog/pg_proc.h 2006-01-24 09:38:15.000000000 +0100 *************** *** 2359,2364 **** --- 2359,2366 ---- DESCR("I/O"); DATA(insert OID = 911 ( inet_out PGNSP PGUID 12 f f t f i 1 2275 "869" _null_ _null_ _null_ inet_out - _null_ )); DESCR("I/O"); + DATA(insert OID = 1265 ( inettocidr PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _null_ _null_ inettocidr - _null_ )); + DESCR("convert inet to cidr"); /* for cidr type support */ DATA(insert OID = 1267 ( cidr_in PGNSP PGUID 12 f f t f i 1 650 "2275" _null_ _null_ _null_ cidr_in - _null_ )); diff -cr cvs/pgsql/src/include/utils/builtins.h cvs.build/pgsql/src/include/utils/builtins.h *** cvs/pgsql/src/include/utils/builtins.h 2006-01-20 13:52:13.000000000 +0100 --- cvs.build/pgsql/src/include/utils/builtins.h 2006-01-24 09:38:15.000000000 +0100 *************** *** 696,701 **** --- 696,702 ---- extern Datum inet_out(PG_FUNCTION_ARGS); extern Datum inet_recv(PG_FUNCTION_ARGS); extern Datum inet_send(PG_FUNCTION_ARGS); + extern Datum inettocidr(PG_FUNCTION_ARGS); extern Datum cidr_in(PG_FUNCTION_ARGS); extern Datum cidr_out(PG_FUNCTION_ARGS); extern Datum cidr_recv(PG_FUNCTION_ARGS); diff -cr cvs/pgsql/src/test/regress/expected/inet.out cvs.build/pgsql/src/test/regress/expected/inet.out *** cvs/pgsql/src/test/regress/expected/inet.out 2004-10-08 03:45:37.000000000 +0200 --- cvs.build/pgsql/src/test/regress/expected/inet.out 2006-01-24 09:38:15.000000000 +0100 *************** *** 242,244 **** --- 242,289 ---- SET enable_seqscan TO on; DROP INDEX inet_idx1; + -- check conversion from inet to cidr (this should zero the unmasked bits) + -- no change expected + SELECT '192.168.255.255/32'::inet::cidr; + cidr + -------------------- + 192.168.255.255/32 + (1 row) + + -- should give 192.168.240.0/20. + SELECT '192.168.255.255/20'::inet::cidr; + cidr + ------------------ + 192.168.240.0/20 + (1 row) + + -- cast every entry from the table + SELECT i, i::cidr FROM INET_TBL; + i | i + ------------------+------------------ + 192.168.1.226/24 | 192.168.1.0/24 + 192.168.1.226 | 192.168.1.226/32 + 192.168.1.0/24 | 192.168.1.0/24 + 192.168.1.0/25 | 192.168.1.0/25 + 192.168.1.255/24 | 192.168.1.0/24 + 192.168.1.255/25 | 192.168.1.128/25 + 10.1.2.3/8 | 10.0.0.0/8 + 10.1.2.3/8 | 10.0.0.0/8 + 10.1.2.3 | 10.1.2.3/32 + 10.1.2.3/24 | 10.1.2.0/24 + 10.1.2.3/16 | 10.1.0.0/16 + 10.1.2.3/8 | 10.0.0.0/8 + 11.1.2.3/8 | 11.0.0.0/8 + 9.1.2.3/8 | 9.0.0.0/8 + 10:23::f1/64 | 10:23::/64 + 10:23::ffff | 10:23::ffff/128 + ::4.3.2.1/24 | ::/24 + (17 rows) + + -- this lost the /32 once... + SELECT '192.168.1.1'::inet::cidr; + cidr + ---------------- + 192.168.1.1/32 + (1 row) + diff -cr cvs/pgsql/src/test/regress/expected/opr_sanity.out cvs.build/pgsql/src/test/regress/expected/opr_sanity.out *** cvs/pgsql/src/test/regress/expected/opr_sanity.out 2005-11-07 18:36:47.000000000 +0100 --- cvs.build/pgsql/src/test/regress/expected/opr_sanity.out 2006-01-24 09:38:15.000000000 +0100 *************** *** 274,279 **** --- 274,283 ---- -- also binary compatible. This is legal, but usually not intended. -- As of 7.4, this finds the casts from text and varchar to bpchar, because -- those are binary-compatible while the reverse way goes through rtrim(). + -- As of 8.2, this finds the cast from CIDR to INET. Both share the same + -- internal representation, but CIDR doesn't allow the unmasked bits to be + -- non-zero. That's why ::CIDR will be cast by means of a function, the + -- other way round is regarded to be a legal binary compatible cast. SELECT * FROM pg_cast c WHERE c.castfunc = 0 AND *************** *** 285,291 **** ------------+------------+----------+------------- 25 | 1042 | 0 | i 1043 | 1042 | 0 | i ! (2 rows) -- **************** pg_operator **************** -- Look for illegal values in pg_operator fields. --- 289,296 ---- ------------+------------+----------+------------- 25 | 1042 | 0 | i 1043 | 1042 | 0 | i ! 650 | 869 | 0 | i ! (3 rows) -- **************** pg_operator **************** -- Look for illegal values in pg_operator fields. diff -cr cvs/pgsql/src/test/regress/sql/inet.sql cvs.build/pgsql/src/test/regress/sql/inet.sql *** cvs/pgsql/src/test/regress/sql/inet.sql 2004-10-08 03:45:37.000000000 +0200 --- cvs.build/pgsql/src/test/regress/sql/inet.sql 2006-01-24 09:38:15.000000000 +0100 *************** *** 65,67 **** --- 65,78 ---- SET enable_seqscan TO on; DROP INDEX inet_idx1; + -- check conversion from inet to cidr (this should zero the unmasked bits) + -- no change expected + SELECT '192.168.255.255/32'::inet::cidr; + -- should give 192.168.240.0/20. + SELECT '192.168.255.255/20'::inet::cidr; + -- cast every entry from the table + SELECT i, i::cidr FROM INET_TBL; + + -- this lost the /32 once... + SELECT '192.168.1.1'::inet::cidr; + diff -cr cvs/pgsql/src/test/regress/sql/opr_sanity.sql cvs.build/pgsql/src/test/regress/sql/opr_sanity.sql *** cvs/pgsql/src/test/regress/sql/opr_sanity.sql 2005-07-01 21:19:05.000000000 +0200 --- cvs.build/pgsql/src/test/regress/sql/opr_sanity.sql 2006-01-24 09:38:15.000000000 +0100 *************** *** 223,228 **** --- 223,233 ---- -- As of 7.4, this finds the casts from text and varchar to bpchar, because -- those are binary-compatible while the reverse way goes through rtrim(). + -- As of 8.2, this finds the cast from CIDR to INET. Both share the same + -- internal representation, but CIDR doesn't allow the unmasked bits to be + -- non-zero. That's why ::CIDR will be cast by means of a function, the + -- other way round is regarded to be a legal binary compatible cast. + SELECT * FROM pg_cast c WHERE c.castfunc = 0 AND