From: Alexander Nozdrin Date: April 6 2011 8:12pm Subject: bzr commit into mysql-trunk branch (alexander.nozdrin:3332) WL#5787 List-Archive: http://lists.mysql.com/commits/134869 Message-Id: <201104062012.p36KCpAO031770@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7331141103821098764==" --===============7331141103821098764== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/alik/MySQL/bzr/00/wl5787/mysql-trunk-wl5787/ based on revid:alexander.nozdrin@stripped 3332 Alexander Nozdrin 2011-04-07 Patch for WL#5787 (IPv6-capable INET_ATON and INET_NTOA functions). The patch introduces the following new functions: - INET6_ATON() - INET6_NTOA() - IS_IPV4() - IS_IPV6() - IS_IPV4_COMPAT() - IS_IPV4_MAPPED() modified: mysql-test/r/func_misc.result mysql-test/t/func_misc.test sql/item_create.cc sql/item_inetfunc.cc sql/item_inetfunc.h === modified file 'mysql-test/r/func_misc.result' --- a/mysql-test/r/func_misc.result 2010-12-17 14:02:56 +0000 +++ b/mysql-test/r/func_misc.result 2011-04-06 20:12:41 +0000 @@ -400,6 +400,483 @@ DROP TABLE t1; # # End of 5.5 tests # + +# -- +# -- WL#5787: IPv6-capable INET_ATON and INET_NTOA functions. +# -- + +# -- INET6_ATON: checking NULL, invalid types, out-of range values... + +SELECT INET6_ATON(NULL) IS NULL; +INET6_ATON(NULL) IS NULL +1 +SELECT INET6_ATON(123) IS NULL; +INET6_ATON(123) IS NULL +1 +SELECT INET6_ATON(123.45) IS NULL; +INET6_ATON(123.45) IS NULL +1 +SELECT INET6_ATON(NOW()) IS NULL; +INET6_ATON(NOW()) IS NULL +1 +SELECT INET6_ATON('1.2.3') IS NULL; +INET6_ATON('1.2.3') IS NULL +1 +SELECT INET6_ATON('1.2.3.') IS NULL; +INET6_ATON('1.2.3.') IS NULL +1 +SELECT INET6_ATON('1..3.4') IS NULL; +INET6_ATON('1..3.4') IS NULL +1 +SELECT INET6_ATON('-1.2.3.4') IS NULL; +INET6_ATON('-1.2.3.4') IS NULL +1 +SELECT INET6_ATON('1.2.3.256') IS NULL; +INET6_ATON('1.2.3.256') IS NULL +1 +SELECT INET6_ATON('1.2.3.4.5') IS NULL; +INET6_ATON('1.2.3.4.5') IS NULL +1 +SELECT INET6_ATON('0001.2.3.4') IS NULL; +INET6_ATON('0001.2.3.4') IS NULL +1 +SELECT INET6_ATON('0x1.2.3.4') IS NULL; +INET6_ATON('0x1.2.3.4') IS NULL +1 +SELECT INET6_ATON('a.2.3.4') IS NULL; +INET6_ATON('a.2.3.4') IS NULL +1 +SELECT INET6_ATON('1.2.3.4:80') IS NULL; +INET6_ATON('1.2.3.4:80') IS NULL +1 +SELECT INET6_ATON('1.2.3.4/32') IS NULL; +INET6_ATON('1.2.3.4/32') IS NULL +1 +SELECT INET6_ATON('mysql.com') IS NULL; +INET6_ATON('mysql.com') IS NULL +1 +SELECT INET6_ATON(':::') IS NULL; +INET6_ATON(':::') IS NULL +1 +SELECT INET6_ATON(':1:2:3') IS NULL; +INET6_ATON(':1:2:3') IS NULL +1 +SELECT INET6_ATON('::00001') IS NULL; +INET6_ATON('::00001') IS NULL +1 +SELECT INET6_ATON('::00001:2') IS NULL; +INET6_ATON('::00001:2') IS NULL +1 +SELECT INET6_ATON('::12345') IS NULL; +INET6_ATON('::12345') IS NULL +1 +SELECT INET6_ATON('1020::3040::5060') IS NULL; +INET6_ATON('1020::3040::5060') IS NULL +1 +SELECT INET6_ATON('::ABCZ') IS NULL; +INET6_ATON('::ABCZ') IS NULL +1 +SELECT INET6_ATON('::0x1.2.3.4') IS NULL; +INET6_ATON('::0x1.2.3.4') IS NULL +1 +SELECT INET6_ATON('::1.0x2.3.4') IS NULL; +INET6_ATON('::1.0x2.3.4') IS NULL +1 +SELECT INET6_ATON('::a.b.c.d') IS NULL; +INET6_ATON('::a.b.c.d') IS NULL +1 +SELECT INET6_ATON('::FFFF:0x1.2.3.4') IS NULL; +INET6_ATON('::FFFF:0x1.2.3.4') IS NULL +1 +SELECT INET6_ATON('::FFFF:1.0x2.3.4') IS NULL; +INET6_ATON('::FFFF:1.0x2.3.4') IS NULL +1 +SELECT INET6_ATON('::FFFF:a.b.c.d') IS NULL; +INET6_ATON('::FFFF:a.b.c.d') IS NULL +1 +SELECT INET6_ATON('::1.2.3.4:ABCD') IS NULL; +INET6_ATON('::1.2.3.4:ABCD') IS NULL +1 +# NOTE: such addresses are supported because getaddrinfo() supports them. +# This is just to record the current behaviour. +SELECT HEX(INET6_ATON('::ABCD:1.2.3.4')); +HEX(INET6_ATON('::ABCD:1.2.3.4')) +00000000000000000000ABCD01020304 + +# -- INET6_ATON: checking binary representation... + +SELECT HEX(INET6_ATON('0.0.0.0')); +HEX(INET6_ATON('0.0.0.0')) +00000000 +SELECT HEX(INET6_ATON('00.00.00.00')); +HEX(INET6_ATON('00.00.00.00')) +00000000 +SELECT HEX(INET6_ATON('000.000.000.000')); +HEX(INET6_ATON('000.000.000.000')) +00000000 +SELECT HEX(INET6_ATON('1.2.3.4')); +HEX(INET6_ATON('1.2.3.4')) +01020304 +SELECT HEX(INET6_ATON('01.02.03.04')); +HEX(INET6_ATON('01.02.03.04')) +01020304 +SELECT HEX(INET6_ATON('001.002.003.004')); +HEX(INET6_ATON('001.002.003.004')) +01020304 +SELECT HEX(INET6_ATON('255.255.255.255')); +HEX(INET6_ATON('255.255.255.255')) +FFFFFFFF +SELECT HEX(INET6_ATON('::')); +HEX(INET6_ATON('::')) +00000000000000000000000000000000 +SELECT HEX(INET6_ATON('0::0')); +HEX(INET6_ATON('0::0')) +00000000000000000000000000000000 +SELECT HEX(INET6_ATON('0::')); +HEX(INET6_ATON('0::')) +00000000000000000000000000000000 +SELECT HEX(INET6_ATON('::0')); +HEX(INET6_ATON('::0')) +00000000000000000000000000000000 +SELECT HEX(INET6_ATON('::1')); +HEX(INET6_ATON('::1')) +00000000000000000000000000000001 +SELECT HEX(INET6_ATON('0000:0000::0000:0001')); +HEX(INET6_ATON('0000:0000::0000:0001')) +00000000000000000000000000000001 +SELECT HEX(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')); +HEX(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')) +00000000000000000000000000000001 +SELECT HEX(INET6_ATON('::C0A8:0102')); +HEX(INET6_ATON('::C0A8:0102')) +000000000000000000000000C0A80102 +SELECT HEX(INET6_ATON('::c0a8:0102')); +HEX(INET6_ATON('::c0a8:0102')) +000000000000000000000000C0A80102 +SELECT HEX(INET6_ATON('::192.168.1.2')); +HEX(INET6_ATON('::192.168.1.2')) +000000000000000000000000C0A80102 +SELECT HEX(INET6_ATON('::FfFf:C0a8:0102')); +HEX(INET6_ATON('::FfFf:C0a8:0102')) +00000000000000000000FFFFC0A80102 +SELECT HEX(INET6_ATON('::ffff:c0a8:0102')); +HEX(INET6_ATON('::ffff:c0a8:0102')) +00000000000000000000FFFFC0A80102 +SELECT HEX(INET6_ATON('::ffff:192.168.1.2')); +HEX(INET6_ATON('::ffff:192.168.1.2')) +00000000000000000000FFFFC0A80102 +SELECT HEX(INET6_ATON('::01.2.3.4')); +HEX(INET6_ATON('::01.2.3.4')) +00000000000000000000000001020304 +SELECT HEX(INET6_ATON('::1.02.3.4')); +HEX(INET6_ATON('::1.02.3.4')) +00000000000000000000000001020304 +SELECT HEX(INET6_ATON('::1.2.03.4')); +HEX(INET6_ATON('::1.2.03.4')) +00000000000000000000000001020304 +SELECT HEX(INET6_ATON('::1.2.3.04')); +HEX(INET6_ATON('::1.2.3.04')) +00000000000000000000000001020304 +SELECT HEX(INET6_ATON('::1.2.3.00')); +HEX(INET6_ATON('::1.2.3.00')) +00000000000000000000000001020300 +SELECT HEX(INET6_ATON('::FFFF:01.2.3.4')); +HEX(INET6_ATON('::FFFF:01.2.3.4')) +00000000000000000000FFFF01020304 +SELECT HEX(INET6_ATON('::FFFF:1.02.3.4')); +HEX(INET6_ATON('::FFFF:1.02.3.4')) +00000000000000000000FFFF01020304 +SELECT HEX(INET6_ATON('::FFFF:1.2.03.4')); +HEX(INET6_ATON('::FFFF:1.2.03.4')) +00000000000000000000FFFF01020304 +SELECT HEX(INET6_ATON('::FFFF:1.2.3.04')); +HEX(INET6_ATON('::FFFF:1.2.3.04')) +00000000000000000000FFFF01020304 +SELECT HEX(INET6_ATON('::FFFF:1.2.3.00')); +HEX(INET6_ATON('::FFFF:1.2.3.00')) +00000000000000000000FFFF01020300 + +# -- INET6_ATON: checking the length is either 4 or 16... + +SELECT LENGTH(INET6_ATON('0.0.0.0')); +LENGTH(INET6_ATON('0.0.0.0')) +4 +SELECT LENGTH(INET6_ATON('255.255.255.255')); +LENGTH(INET6_ATON('255.255.255.255')) +4 +SELECT LENGTH(INET6_ATON('::')); +LENGTH(INET6_ATON('::')) +16 +SELECT LENGTH(INET6_ATON('1020:3040:5060:7080:90A0:B0C0:D0E0:F010')); +LENGTH(INET6_ATON('1020:3040:5060:7080:90A0:B0C0:D0E0:F010')) +16 + +# -- INET6_NTOA: checking NULL, invalid types, out-of range values... + +SELECT INET6_NTOA(NULL); +INET6_NTOA(NULL) +NULL +SELECT INET6_NTOA(123); +INET6_NTOA(123) +NULL +SELECT INET6_NTOA(123.456); +INET6_NTOA(123.456) +NULL +SELECT INET6_NTOA(NOW()); +INET6_NTOA(NOW()) +NULL +SELECT INET6_NTOA(UNHEX('C0A801')); +INET6_NTOA(UNHEX('C0A801')) +NULL +SELECT INET6_NTOA(UNHEX('C0A80102')); +INET6_NTOA(UNHEX('C0A80102')) +192.168.1.2 +SELECT INET6_NTOA(UNHEX('C0A8010203')); +INET6_NTOA(UNHEX('C0A8010203')) +NULL +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F')); +INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F')) +NULL +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F10')); +INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F10')) +102:304:506:708:90a:b0c:d0e:f10 +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F1011')); +INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F1011')) +NULL +SELECT INET6_NTOA('1234'), INET6_NTOA(BINARY('1234')); +INET6_NTOA('1234') INET6_NTOA(BINARY('1234')) +NULL 49.50.51.52 +SELECT INET6_NTOA('0123456789abcdef'), INET6_NTOA(BINARY('0123456789abcdef')); +INET6_NTOA('0123456789abcdef') INET6_NTOA(BINARY('0123456789abcdef')) +NULL 3031:3233:3435:3637:3839:6162:6364:6566 + +# -- Checking double-conversion... + +SELECT INET6_NTOA(INET6_ATON('::')); +INET6_NTOA(INET6_ATON('::')) +:: +SELECT INET6_NTOA(INET6_ATON('0::0')); +INET6_NTOA(INET6_ATON('0::0')) +:: +SELECT INET6_NTOA(INET6_ATON('0::')); +INET6_NTOA(INET6_ATON('0::')) +:: +SELECT INET6_NTOA(INET6_ATON('::0')); +INET6_NTOA(INET6_ATON('::0')) +:: +SELECT INET6_NTOA(INET6_ATON('::1')); +INET6_NTOA(INET6_ATON('::1')) +::1 +SELECT INET6_NTOA(INET6_ATON('0000:0000::0000:0001')); +INET6_NTOA(INET6_ATON('0000:0000::0000:0001')) +::1 +SELECT INET6_NTOA(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')); +INET6_NTOA(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')) +::1 +SELECT INET6_NTOA(INET6_ATON('::C0A8:0102')); +INET6_NTOA(INET6_ATON('::C0A8:0102')) +::192.168.1.2 +SELECT INET6_NTOA(INET6_ATON('::c0a8:0102')); +INET6_NTOA(INET6_ATON('::c0a8:0102')) +::192.168.1.2 +SELECT INET6_NTOA(INET6_ATON('::192.168.1.2')); +INET6_NTOA(INET6_ATON('::192.168.1.2')) +::192.168.1.2 +SELECT INET6_NTOA(INET6_ATON('::FFFF:C0A8:0102')); +INET6_NTOA(INET6_ATON('::FFFF:C0A8:0102')) +::ffff:192.168.1.2 +SELECT INET6_NTOA(INET6_ATON('::ffff:c0a8:0102')); +INET6_NTOA(INET6_ATON('::ffff:c0a8:0102')) +::ffff:192.168.1.2 +SELECT INET6_NTOA(INET6_ATON('::ffff:192.168.1.2')); +INET6_NTOA(INET6_ATON('::ffff:192.168.1.2')) +::ffff:192.168.1.2 + +# -- Comparing INET_ATON() and INET6_ATON()... + +SELECT HEX(INET_ATON('192.168.1.2')); +HEX(INET_ATON('192.168.1.2')) +C0A80102 +SELECT HEX(INET6_ATON('192.168.1.2')); +HEX(INET6_ATON('192.168.1.2')) +C0A80102 +SELECT HEX(INET_ATON('255.255.255.255')); +HEX(INET_ATON('255.255.255.255')) +FFFFFFFF +SELECT HEX(INET6_ATON('255.255.255.255')); +HEX(INET6_ATON('255.255.255.255')) +FFFFFFFF +SELECT HEX(INET_ATON('192.168.08.2')); +HEX(INET_ATON('192.168.08.2')) +C0A80802 +SELECT HEX(INET6_ATON('192.168.08.2')); +HEX(INET6_ATON('192.168.08.2')) +C0A80802 +SELECT HEX(INET_ATON('192.168.0x8.2')); +HEX(INET_ATON('192.168.0x8.2')) +NULL +SELECT HEX(INET6_ATON('192.168.0x8.2')); +HEX(INET6_ATON('192.168.0x8.2')) +NULL +SELECT HEX(INET_ATON('1.2.255')); +HEX(INET_ATON('1.2.255')) +10200FF +SELECT HEX(INET6_ATON('1.2.255')); +HEX(INET6_ATON('1.2.255')) +NULL +SELECT HEX(INET_ATON('1.2.256')); +HEX(INET_ATON('1.2.256')) +NULL +SELECT HEX(INET6_ATON('1.2.256')); +HEX(INET6_ATON('1.2.256')) +NULL +SELECT HEX(INET_ATON('1.0002.3.4')); +HEX(INET_ATON('1.0002.3.4')) +1020304 +SELECT HEX(INET6_ATON('1.0002.3.4')); +HEX(INET6_ATON('1.0002.3.4')) +NULL +SELECT HEX(INET_ATON('1.2.3.4.5')); +HEX(INET_ATON('1.2.3.4.5')) +102030405 +SELECT HEX(INET6_ATON('1.2.3.4.5')); +HEX(INET6_ATON('1.2.3.4.5')) +NULL + +# -- Checking mix of INET- and INET6- functions... + +SELECT HEX(INET6_ATON(INET_NTOA(INET_ATON('1.2.3.4')))) AS x; +x +01020304 + +# -- Checking IS_IPV4() / IS_IPV6()... + +SELECT IS_IPV4(NULL); +IS_IPV4(NULL) +0 +SELECT IS_IPV4(1); +IS_IPV4(1) +0 +SELECT IS_IPV4(1.0); +IS_IPV4(1.0) +0 +SELECT IS_IPV4('1.2.3.4'); +IS_IPV4('1.2.3.4') +1 +SELECT IS_IPV4('001.02.000.255'); +IS_IPV4('001.02.000.255') +1 +SELECT IS_IPV4('::1.2.0.255'); +IS_IPV4('::1.2.0.255') +0 +SELECT IS_IPV4('::1'); +IS_IPV4('::1') +0 +SELECT IS_IPV4(BINARY('1.2.3.4')); +IS_IPV4(BINARY('1.2.3.4')) +1 +SELECT IS_IPV6(NULL); +IS_IPV6(NULL) +0 +SELECT IS_IPV6(1); +IS_IPV6(1) +0 +SELECT IS_IPV6(1.0); +IS_IPV6(1.0) +0 +SELECT IS_IPV6('1.2.3.4'); +IS_IPV6('1.2.3.4') +0 +SELECT IS_IPV6('001.02.000.255'); +IS_IPV6('001.02.000.255') +0 +SELECT IS_IPV6('::001.02.000.255'); +IS_IPV6('::001.02.000.255') +1 +SELECT IS_IPV6('::1.2.0.255'); +IS_IPV6('::1.2.0.255') +1 +SELECT IS_IPV6('::1'); +IS_IPV6('::1') +1 +SELECT IS_IPV6('0000:0000:0000:0000:0000:0000:0000:0001'); +IS_IPV6('0000:0000:0000:0000:0000:0000:0000:0001') +1 +SELECT IS_IPV6(BINARY('0000:0000:0000:0000:0000:0000:0000:0001')); +IS_IPV6(BINARY('0000:0000:0000:0000:0000:0000:0000:0001')) +1 + +# -- Checking IS_IPV4_MAPPED() and IS_IPV4_COMPAT()... + +SELECT IS_IPV4_MAPPED(INET6_ATON('1.2.3.4')), +IS_IPV4_COMPAT(INET6_ATON('1.2.3.4')); +IS_IPV4_MAPPED(INET6_ATON('1.2.3.4')) IS_IPV4_COMPAT(INET6_ATON('1.2.3.4')) +0 0 +SELECT IS_IPV4_MAPPED(INET6_ATON('::1.2.3.4')), +IS_IPV4_COMPAT(INET6_ATON('::1.2.3.4')); +IS_IPV4_MAPPED(INET6_ATON('::1.2.3.4')) IS_IPV4_COMPAT(INET6_ATON('::1.2.3.4')) +0 1 +SELECT IS_IPV4_MAPPED(INET6_ATON('::FFFF:1.2.3.4')), +IS_IPV4_COMPAT(INET6_ATON('::FFFF:1.2.3.4')); +IS_IPV4_MAPPED(INET6_ATON('::FFFF:1.2.3.4')) IS_IPV4_COMPAT(INET6_ATON('::FFFF:1.2.3.4')) +1 0 +SELECT IS_IPV4_MAPPED(INET6_ATON('::ABCD:1.2.3.4')), +IS_IPV4_COMPAT(INET6_ATON('::ABCD:1.2.3.4')); +IS_IPV4_MAPPED(INET6_ATON('::ABCD:1.2.3.4')) IS_IPV4_COMPAT(INET6_ATON('::ABCD:1.2.3.4')) +0 0 +SELECT IS_IPV4_MAPPED(INET6_ATON('::1')), +IS_IPV4_COMPAT(INET6_ATON('::1')); +IS_IPV4_MAPPED(INET6_ATON('::1')) IS_IPV4_COMPAT(INET6_ATON('::1')) +0 0 +SELECT IS_IPV4_MAPPED(INET6_ATON('::')), +IS_IPV4_COMPAT(INET6_ATON('::')); +IS_IPV4_MAPPED(INET6_ATON('::')) IS_IPV4_COMPAT(INET6_ATON('::')) +0 0 + +# -- Checking IS_IPV4_COMPAT()... + + +# -- Working with a table... + +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1(ip INT UNSIGNED); +CREATE TABLE t2(ip VARBINARY(16)); + +INSERT INTO t1 VALUES +(INET_ATON('1.2.3.4')), (INET_ATON('255.255.255.255')); +SELECT INET_NTOA(ip) FROM t1; +INET_NTOA(ip) +1.2.3.4 +255.255.255.255 + +INSERT INTO t2 SELECT INET6_ATON(INET_NTOA(ip)) FROM t1; +SELECT INET6_NTOA(ip), HEX(ip), LENGTH(ip) FROM t2; +INET6_NTOA(ip) HEX(ip) LENGTH(ip) +1.2.3.4 01020304 4 +255.255.255.255 FFFFFFFF 4 +DELETE FROM t2; + +INSERT INTO t2 VALUES +(INET6_ATON('1.2.3.4')), (INET6_ATON('255.255.255.255')), +(INET6_ATON('::1.2.3.4')), (INET6_ATON('::ffff:255.255.255.255')), +(INET6_ATON('::')), (INET6_ATON('::1')), +(INET6_ATON('1020:3040:5060:7080:90A0:B0C0:D0E0:F010')); +SELECT INET6_NTOA(ip), HEX(ip), LENGTH(ip) FROM t2; +INET6_NTOA(ip) HEX(ip) LENGTH(ip) +1.2.3.4 01020304 4 +255.255.255.255 FFFFFFFF 4 +::1.2.3.4 00000000000000000000000001020304 16 +::ffff:255.255.255.255 00000000000000000000FFFFFFFFFFFF 16 +:: 00000000000000000000000000000000 16 +::1 00000000000000000000000000000001 16 +1020:3040:5060:7080:90a0:b0c0:d0e0:f010 102030405060708090A0B0C0D0E0F010 16 + +DROP TABLE t1; +DROP TABLE t2; + +# -- Done. + # # End of tests # === modified file 'mysql-test/t/func_misc.test' --- a/mysql-test/t/func_misc.test 2010-12-17 14:02:56 +0000 +++ b/mysql-test/t/func_misc.test 2011-04-06 20:12:41 +0000 @@ -541,6 +541,262 @@ DROP TABLE t1; --echo # End of 5.5 tests --echo # +--echo +--echo # -- +--echo # -- WL#5787: IPv6-capable INET_ATON and INET_NTOA functions. +--echo # -- + +--echo +--echo # -- INET6_ATON: checking NULL, invalid types, out-of range values... +--echo + +SELECT INET6_ATON(NULL) IS NULL; +SELECT INET6_ATON(123) IS NULL; +SELECT INET6_ATON(123.45) IS NULL; +SELECT INET6_ATON(NOW()) IS NULL; + +SELECT INET6_ATON('1.2.3') IS NULL; +SELECT INET6_ATON('1.2.3.') IS NULL; +SELECT INET6_ATON('1..3.4') IS NULL; +SELECT INET6_ATON('-1.2.3.4') IS NULL; +SELECT INET6_ATON('1.2.3.256') IS NULL; +SELECT INET6_ATON('1.2.3.4.5') IS NULL; +SELECT INET6_ATON('0001.2.3.4') IS NULL; +SELECT INET6_ATON('0x1.2.3.4') IS NULL; +SELECT INET6_ATON('a.2.3.4') IS NULL; + +SELECT INET6_ATON('1.2.3.4:80') IS NULL; +SELECT INET6_ATON('1.2.3.4/32') IS NULL; + +SELECT INET6_ATON('mysql.com') IS NULL; + +SELECT INET6_ATON(':::') IS NULL; +SELECT INET6_ATON(':1:2:3') IS NULL; +SELECT INET6_ATON('::00001') IS NULL; +SELECT INET6_ATON('::00001:2') IS NULL; +SELECT INET6_ATON('::12345') IS NULL; +SELECT INET6_ATON('1020::3040::5060') IS NULL; +SELECT INET6_ATON('::ABCZ') IS NULL; + +SELECT INET6_ATON('::0x1.2.3.4') IS NULL; +SELECT INET6_ATON('::1.0x2.3.4') IS NULL; +SELECT INET6_ATON('::a.b.c.d') IS NULL; + +SELECT INET6_ATON('::FFFF:0x1.2.3.4') IS NULL; +SELECT INET6_ATON('::FFFF:1.0x2.3.4') IS NULL; +SELECT INET6_ATON('::FFFF:a.b.c.d') IS NULL; + +SELECT INET6_ATON('::1.2.3.4:ABCD') IS NULL; + +--echo # NOTE: such addresses are supported because getaddrinfo() supports them. +--echo # This is just to record the current behaviour. +SELECT HEX(INET6_ATON('::ABCD:1.2.3.4')); + +--echo +--echo # -- INET6_ATON: checking binary representation... +--echo + +SELECT HEX(INET6_ATON('0.0.0.0')); +SELECT HEX(INET6_ATON('00.00.00.00')); +SELECT HEX(INET6_ATON('000.000.000.000')); +SELECT HEX(INET6_ATON('1.2.3.4')); +SELECT HEX(INET6_ATON('01.02.03.04')); +SELECT HEX(INET6_ATON('001.002.003.004')); +SELECT HEX(INET6_ATON('255.255.255.255')); +SELECT HEX(INET6_ATON('::')); +SELECT HEX(INET6_ATON('0::0')); +SELECT HEX(INET6_ATON('0::')); +SELECT HEX(INET6_ATON('::0')); +SELECT HEX(INET6_ATON('::1')); +SELECT HEX(INET6_ATON('0000:0000::0000:0001')); +SELECT HEX(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')); +SELECT HEX(INET6_ATON('::C0A8:0102')); +SELECT HEX(INET6_ATON('::c0a8:0102')); +SELECT HEX(INET6_ATON('::192.168.1.2')); +SELECT HEX(INET6_ATON('::FfFf:C0a8:0102')); +SELECT HEX(INET6_ATON('::ffff:c0a8:0102')); +SELECT HEX(INET6_ATON('::ffff:192.168.1.2')); +SELECT HEX(INET6_ATON('::01.2.3.4')); +SELECT HEX(INET6_ATON('::1.02.3.4')); +SELECT HEX(INET6_ATON('::1.2.03.4')); +SELECT HEX(INET6_ATON('::1.2.3.04')); +SELECT HEX(INET6_ATON('::1.2.3.00')); +SELECT HEX(INET6_ATON('::FFFF:01.2.3.4')); +SELECT HEX(INET6_ATON('::FFFF:1.02.3.4')); +SELECT HEX(INET6_ATON('::FFFF:1.2.03.4')); +SELECT HEX(INET6_ATON('::FFFF:1.2.3.04')); +SELECT HEX(INET6_ATON('::FFFF:1.2.3.00')); + +--echo +--echo # -- INET6_ATON: checking the length is either 4 or 16... +--echo + +SELECT LENGTH(INET6_ATON('0.0.0.0')); +SELECT LENGTH(INET6_ATON('255.255.255.255')); +SELECT LENGTH(INET6_ATON('::')); +SELECT LENGTH(INET6_ATON('1020:3040:5060:7080:90A0:B0C0:D0E0:F010')); + +--echo +--echo # -- INET6_NTOA: checking NULL, invalid types, out-of range values... +--echo + +SELECT INET6_NTOA(NULL); +SELECT INET6_NTOA(123); +SELECT INET6_NTOA(123.456); +SELECT INET6_NTOA(NOW()); +SELECT INET6_NTOA(UNHEX('C0A801')); # 3 bytes -> NULL +SELECT INET6_NTOA(UNHEX('C0A80102')); # 4 bytes -> 192.168.1.2 +SELECT INET6_NTOA(UNHEX('C0A8010203')); # 5 bytes -> NULL +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F')); # 15 bytes -> NULL +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F10')); # 16 bytes -> IP +SELECT INET6_NTOA(UNHEX('0102030405060708090A0B0C0D0E0F1011')); # 17 bytes -> NULL + +SELECT INET6_NTOA('1234'), INET6_NTOA(BINARY('1234')); +SELECT INET6_NTOA('0123456789abcdef'), INET6_NTOA(BINARY('0123456789abcdef')); + +--echo +--echo # -- Checking double-conversion... +--echo + +SELECT INET6_NTOA(INET6_ATON('::')); +SELECT INET6_NTOA(INET6_ATON('0::0')); +SELECT INET6_NTOA(INET6_ATON('0::')); +SELECT INET6_NTOA(INET6_ATON('::0')); +SELECT INET6_NTOA(INET6_ATON('::1')); +SELECT INET6_NTOA(INET6_ATON('0000:0000::0000:0001')); +SELECT INET6_NTOA(INET6_ATON('0000:0000:0000:0000:0000:0000:0000:0001')); +SELECT INET6_NTOA(INET6_ATON('::C0A8:0102')); +SELECT INET6_NTOA(INET6_ATON('::c0a8:0102')); +SELECT INET6_NTOA(INET6_ATON('::192.168.1.2')); +SELECT INET6_NTOA(INET6_ATON('::FFFF:C0A8:0102')); +SELECT INET6_NTOA(INET6_ATON('::ffff:c0a8:0102')); +SELECT INET6_NTOA(INET6_ATON('::ffff:192.168.1.2')); + +--echo +--echo # -- Comparing INET_ATON() and INET6_ATON()... +--echo + +SELECT HEX(INET_ATON('192.168.1.2')); +SELECT HEX(INET6_ATON('192.168.1.2')); + +SELECT HEX(INET_ATON('255.255.255.255')); +SELECT HEX(INET6_ATON('255.255.255.255')); + +SELECT HEX(INET_ATON('192.168.08.2')); +SELECT HEX(INET6_ATON('192.168.08.2')); + +SELECT HEX(INET_ATON('192.168.0x8.2')); +SELECT HEX(INET6_ATON('192.168.0x8.2')); + +SELECT HEX(INET_ATON('1.2.255')); +SELECT HEX(INET6_ATON('1.2.255')); + +SELECT HEX(INET_ATON('1.2.256')); +SELECT HEX(INET6_ATON('1.2.256')); + +SELECT HEX(INET_ATON('1.0002.3.4')); +SELECT HEX(INET6_ATON('1.0002.3.4')); + +SELECT HEX(INET_ATON('1.2.3.4.5')); +SELECT HEX(INET6_ATON('1.2.3.4.5')); + +--echo +--echo # -- Checking mix of INET- and INET6- functions... +--echo + +SELECT HEX(INET6_ATON(INET_NTOA(INET_ATON('1.2.3.4')))) AS x; + +--echo +--echo # -- Checking IS_IPV4() / IS_IPV6()... +--echo + +SELECT IS_IPV4(NULL); +SELECT IS_IPV4(1); +SELECT IS_IPV4(1.0); +SELECT IS_IPV4('1.2.3.4'); +SELECT IS_IPV4('001.02.000.255'); +SELECT IS_IPV4('::1.2.0.255'); +SELECT IS_IPV4('::1'); +SELECT IS_IPV4(BINARY('1.2.3.4')); + +SELECT IS_IPV6(NULL); +SELECT IS_IPV6(1); +SELECT IS_IPV6(1.0); +SELECT IS_IPV6('1.2.3.4'); +SELECT IS_IPV6('001.02.000.255'); +SELECT IS_IPV6('::001.02.000.255'); +SELECT IS_IPV6('::1.2.0.255'); +SELECT IS_IPV6('::1'); +SELECT IS_IPV6('0000:0000:0000:0000:0000:0000:0000:0001'); +SELECT IS_IPV6(BINARY('0000:0000:0000:0000:0000:0000:0000:0001')); + +--echo +--echo # -- Checking IS_IPV4_MAPPED() and IS_IPV4_COMPAT()... +--echo + +SELECT IS_IPV4_MAPPED(INET6_ATON('1.2.3.4')), + IS_IPV4_COMPAT(INET6_ATON('1.2.3.4')); +SELECT IS_IPV4_MAPPED(INET6_ATON('::1.2.3.4')), + IS_IPV4_COMPAT(INET6_ATON('::1.2.3.4')); +SELECT IS_IPV4_MAPPED(INET6_ATON('::FFFF:1.2.3.4')), + IS_IPV4_COMPAT(INET6_ATON('::FFFF:1.2.3.4')); +SELECT IS_IPV4_MAPPED(INET6_ATON('::ABCD:1.2.3.4')), + IS_IPV4_COMPAT(INET6_ATON('::ABCD:1.2.3.4')); +SELECT IS_IPV4_MAPPED(INET6_ATON('::1')), + IS_IPV4_COMPAT(INET6_ATON('::1')); +SELECT IS_IPV4_MAPPED(INET6_ATON('::')), + IS_IPV4_COMPAT(INET6_ATON('::')); + +# NOTE: IS_IPV4_COMPAT() / IS_IPV4_MAPPED() could work with "regular strings in +# binary collation" too, but there is no way to create a "regular string" +# starting with \0. + +--echo +--echo # -- Checking IS_IPV4_COMPAT()... +--echo + +--echo +--echo # -- Working with a table... +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +CREATE TABLE t1(ip INT UNSIGNED); +CREATE TABLE t2(ip VARBINARY(16)); + +--echo + +INSERT INTO t1 VALUES + (INET_ATON('1.2.3.4')), (INET_ATON('255.255.255.255')); +SELECT INET_NTOA(ip) FROM t1; + +--echo + +INSERT INTO t2 SELECT INET6_ATON(INET_NTOA(ip)) FROM t1; +SELECT INET6_NTOA(ip), HEX(ip), LENGTH(ip) FROM t2; +DELETE FROM t2; + +--echo + +INSERT INTO t2 VALUES + (INET6_ATON('1.2.3.4')), (INET6_ATON('255.255.255.255')), + (INET6_ATON('::1.2.3.4')), (INET6_ATON('::ffff:255.255.255.255')), + (INET6_ATON('::')), (INET6_ATON('::1')), + (INET6_ATON('1020:3040:5060:7080:90A0:B0C0:D0E0:F010')); +SELECT INET6_NTOA(ip), HEX(ip), LENGTH(ip) FROM t2; + +--echo + +DROP TABLE t1; +DROP TABLE t2; + +--echo +--echo # -- Done. +--echo + --echo # --echo # End of tests --echo # === modified file 'sql/item_create.cc' --- a/sql/item_create.cc 2011-03-29 13:25:20 +0000 +++ b/sql/item_create.cc 2011-04-06 20:12:41 +0000 @@ -1204,6 +1204,84 @@ protected: }; +class Create_func_inet6_aton : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_inet6_aton s_singleton; + +protected: + Create_func_inet6_aton() {} + virtual ~Create_func_inet6_aton() {} +}; + + +class Create_func_inet6_ntoa : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_inet6_ntoa s_singleton; + +protected: + Create_func_inet6_ntoa() {} + virtual ~Create_func_inet6_ntoa() {} +}; + + +class Create_func_is_ipv4 : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_is_ipv4 s_singleton; + +protected: + Create_func_is_ipv4() {} + virtual ~Create_func_is_ipv4() {} +}; + + +class Create_func_is_ipv6 : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_is_ipv6 s_singleton; + +protected: + Create_func_is_ipv6() {} + virtual ~Create_func_is_ipv6() {} +}; + + +class Create_func_is_ipv4_compat : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_is_ipv4_compat s_singleton; + +protected: + Create_func_is_ipv4_compat() {} + virtual ~Create_func_is_ipv4_compat() {} +}; + + +class Create_func_is_ipv4_mapped : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_is_ipv4_mapped s_singleton; + +protected: + Create_func_is_ipv4_mapped() {} + virtual ~Create_func_is_ipv4_mapped() {} +}; + + class Create_func_instr : public Create_func_arg2 { public: @@ -3904,6 +3982,24 @@ Create_func_inet_ntoa::create(THD *thd, } +Create_func_inet6_aton Create_func_inet6_aton::s_singleton; + +Item* +Create_func_inet6_aton::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_inet6_aton(arg1); +} + + +Create_func_inet6_ntoa Create_func_inet6_ntoa::s_singleton; + +Item* +Create_func_inet6_ntoa::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_inet6_ntoa(arg1); +} + + Create_func_inet_aton Create_func_inet_aton::s_singleton; Item* @@ -3913,6 +4009,42 @@ Create_func_inet_aton::create(THD *thd, } +Create_func_is_ipv4 Create_func_is_ipv4::s_singleton; + +Item* +Create_func_is_ipv4::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_is_ipv4(arg1); +} + + +Create_func_is_ipv6 Create_func_is_ipv6::s_singleton; + +Item* +Create_func_is_ipv6::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_is_ipv6(arg1); +} + + +Create_func_is_ipv4_compat Create_func_is_ipv4_compat::s_singleton; + +Item* +Create_func_is_ipv4_compat::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_is_ipv4_compat(arg1); +} + + +Create_func_is_ipv4_mapped Create_func_is_ipv4_mapped::s_singleton; + +Item* +Create_func_is_ipv4_mapped::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_is_ipv4_mapped(arg1); +} + + Create_func_instr Create_func_instr::s_singleton; Item* @@ -5279,6 +5411,12 @@ static Native_func_registry func_array[] { { C_STRING_WITH_LEN("IFNULL") }, BUILDER(Create_func_ifnull)}, { { C_STRING_WITH_LEN("INET_ATON") }, BUILDER(Create_func_inet_aton)}, { { C_STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)}, + { { C_STRING_WITH_LEN("INET6_ATON") }, BUILDER(Create_func_inet6_aton)}, + { { C_STRING_WITH_LEN("INET6_NTOA") }, BUILDER(Create_func_inet6_ntoa)}, + { { C_STRING_WITH_LEN("IS_IPV4") }, BUILDER(Create_func_is_ipv4)}, + { { C_STRING_WITH_LEN("IS_IPV6") }, BUILDER(Create_func_is_ipv6)}, + { { C_STRING_WITH_LEN("IS_IPV4_COMPAT") }, BUILDER(Create_func_is_ipv4_compat)}, + { { C_STRING_WITH_LEN("IS_IPV4_MAPPED") }, BUILDER(Create_func_is_ipv4_mapped)}, { { C_STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)}, { { C_STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)}, { { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)}, === modified file 'sql/item_inetfunc.cc' --- a/sql/item_inetfunc.cc 2011-04-06 20:03:33 +0000 +++ b/sql/item_inetfunc.cc 2011-04-06 20:12:41 +0000 @@ -18,6 +18,12 @@ #include "violite.h" // vio_getnameinfo() #include "log.h" // sql_print_warning() +/////////////////////////////////////////////////////////////////////////// + +static const unsigned int IN_ADDR_SIZE= sizeof (in_addr); +static const unsigned int IN6_ADDR_SIZE= sizeof (in6_addr); + +static const char HEX_DIGITS[]= "0123456789abcdef"; /////////////////////////////////////////////////////////////////////////// @@ -133,3 +139,566 @@ String* Item_func_inet_ntoa::val_str(Str return str; } + +/////////////////////////////////////////////////////////////////////////// + +/** + Check the function argument, handle errors properly. + + @return The function value. +*/ + +longlong Item_func_inet_bool_base::val_int() +{ + DBUG_ASSERT(fixed); + + if (args[0]->result_type() != STRING_RESULT || // String argument expected + args[0]->null_value) // Not-NULL argument expected + return 0; + + String buffer; + String *arg_str= args[0]->val_str(&buffer); + + if (!arg_str) // Out-of memory happened. The error has been reported. + return 0; + + return calc_value(arg_str) ? 1 : 0; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Check the function argument, handle errors properly. + + @param [out] buffer Buffer for string operations. + + @return The function value. +*/ + +String *Item_func_inet_str_base::val_str_ascii(String *buffer) +{ + DBUG_ASSERT(fixed); + + if (args[0]->result_type() != STRING_RESULT || // String argument expected + args[0]->null_value) // Not-NULL argument expected + { + null_value= true; + return NULL; + } + + String *arg_str= args[0]->val_str(buffer); + + if (!arg_str) // Out-of memory happened. The error has been reported. + { + null_value= true; + return NULL; + } + + null_value= !calc_value(arg_str, buffer); + + return null_value ? NULL : buffer; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Tries to convert given string to binary IPv4-address representation. + + @param str String to convert. + @param str_len String length. + @param[out] ipv4_address Buffer to store IPv4-address. + + @return Completion status. + @retval false Given string does not represent an IPv4-address. + @retval true The string has been converted sucessfully. +*/ + +static bool str_to_ipv4(const char *str, int str_length, in_addr *ipv4_address) +{ + if (str_length < 7) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): " + "invalid IPv4 address: too short.", + str_length, str)); + return false; + } + + if (str_length > 15) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): " + "invalid IPv4 address: too long.", + str_length, str)); + return false; + } + + unsigned char *ipv4_bytes= (unsigned char *) ipv4_address; + const char *p= str; + int byte_value= 0; + int chars_in_group= 0; + int dot_count= 0; + char c; + + while (*p && ((p - str) < str_length)) + { + c= *p++; + + if (my_isdigit(&my_charset_latin1, c)) + { + ++chars_in_group; + + if (chars_in_group > 3) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "too many characters in a group.", + str_length, str)); + return false; + } + + byte_value= byte_value * 10 + (c - '0'); + + if (byte_value > 255) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "invalid byte value.", + str_length, str)); + return false; + } + } + else if (c == '.') + { + if (chars_in_group == 0) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "too few characters in a group.", + str_length, str)); + return false; + } + + ipv4_bytes[dot_count]= (unsigned char) byte_value; + + ++dot_count; + byte_value= 0; + chars_in_group= 0; + + if (dot_count > 3) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "too many dots.", str_length, str)); + return false; + } + } + else + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "invalid character at pos %d.", + str_length, str, (int) (p - str))); + return false; + } + } + + if (c == '.') + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "ending at '.'.", str_length, str)); + return false; + } + + if (dot_count != 3) + { + DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " + "classful address (too few groups).", + str_length, str)); + return false; + } + + ipv4_bytes[3]= (unsigned char) byte_value; + + DBUG_PRINT("info", ("str_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d", + str_length, str, + ipv4_bytes[0], ipv4_bytes[1], + ipv4_bytes[2], ipv4_bytes[3])); + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Tries to convert given string to binary IPv6-address representation. + + @param str String to convert. + @param str_len String length. + @param[out] ipv6_address Buffer to store IPv6-address. + + @return Completion status. + @retval false Given string does not represent an IPv6-address. + @retval true The string has been converted sucessfully. +*/ + +static bool str_to_ipv6(const char *str, int str_length, in6_addr *ipv6_address) +{ + if (str_length < 2) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too short.", + str_length, str)); + return false; + } + + if (str_length > 8 * 4 + 7) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too long.", + str_length, str)); + return false; + } + + bzero(ipv6_address, IN6_ADDR_SIZE); + + const char *p= str; + + if (*p == ':') + { + ++p; + + if (*p != ':') + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "can not start with ':x'.", str_length, str)); + return false; + } + } + + char *ipv6_bytes= (char *) ipv6_address; + char *ipv6_bytes_end= ipv6_bytes + IN6_ADDR_SIZE; + char *dst= ipv6_bytes; + char *gap_ptr= NULL; + const char *group_start_ptr= p; + int chars_in_group= 0; + int group_value= 0; + + while (*p) + { + char c= *p++; + + if (c == ':') + { + group_start_ptr= p; + + if (!chars_in_group) + { + if (gap_ptr) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "too many gaps(::).", str_length, str)); + return false; + } + + gap_ptr= dst; + continue; + } + + if (!*p) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "ending at ':'.", str_length, str)); + return false; + } + + if (dst + 2 > ipv6_bytes_end) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "too many groups (1).", str_length, str)); + return false; + } + + dst[0]= (unsigned char) (group_value >> 8) & 0xff; + dst[1]= (unsigned char) group_value & 0xff; + dst += 2; + + chars_in_group= 0; + group_value= 0; + } + else if (c == '.') + { + if (dst + IN_ADDR_SIZE > ipv6_bytes_end) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "unexpected IPv4-part.", str_length, str)); + return false; + } + + if (!str_to_ipv4(group_start_ptr, + str + str_length - group_start_ptr, + (in_addr *) dst)) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "invalid IPv4-part.", str_length, str)); + return false; + } + + dst += IN_ADDR_SIZE; + chars_in_group= 0; + + break; + } + else + { + const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c)); + + if (!hdp) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "invalid character at pos %d.", + str_length, str, (int) (p - str))); + return false; + } + + if (chars_in_group >= 4) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "too many digits in group.", + str_length, str)); + return false; + } + + group_value <<= 4; + group_value |= hdp - HEX_DIGITS; + + DBUG_ASSERT(group_value <= 0xffff); + + ++chars_in_group; + } + } + + if (chars_in_group > 0) + { + if (dst + 2 > ipv6_bytes_end) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "too many groups (2).", str_length, str)); + return false; + } + + dst[0]= (unsigned char) (group_value >> 8) & 0xff; + dst[1]= (unsigned char) group_value & 0xff; + dst += 2; + } + + if (gap_ptr) + { + if (dst == ipv6_bytes_end) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "no room for a gap (::).", str_length, str)); + return false; + } + + int bytes_to_move= dst - gap_ptr; + + memmove(ipv6_bytes_end - bytes_to_move, gap_ptr, bytes_to_move); + bzero(gap_ptr, bytes_to_move); + + dst= ipv6_bytes_end; + } + + if (dst < ipv6_bytes_end) + { + DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " + "too few groups.", str_length, str)); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Converts IP-address-string to IP-address-data. + + @param arg IP-address-string. + @param [out] buffer Buffer to store IP-address-data. + + @return Completion status. + @retval false Given string does not represent an IP-address. + @retval true The string has been converted sucessfully. +*/ + +bool Item_func_inet6_aton::calc_value(String *arg, String *buffer) +{ + // ipv4-string -> varbinary(4) + // ipv6-string -> varbinary(16) + + in_addr ipv4_address; + in6_addr ipv6_address; + + if (str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address)) + { + buffer->length(0); + buffer->append((char *) &ipv4_address, sizeof (in_addr), &my_charset_bin); + + return true; + } + + if (str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address)) + { + buffer->length(0); + buffer->append((char *) &ipv6_address, sizeof (in6_addr), &my_charset_bin); + + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Converts IP-address-data to IP-address-string. + + @param arg IP-address-data. + @param [out] buffer Buffer to store IP-address-string. + + @return Completion status. + @retval false The argument does not correspond to IP-address. + @retval true The string has been converted sucessfully. +*/ + +bool Item_func_inet6_ntoa::calc_value(String *arg, String *buffer) +{ + if (arg->charset() != &my_charset_bin) + return false; + + if (arg->length() == IN_ADDR_SIZE) + { + sockaddr_in ip4; + bzero(&ip4, sizeof (ip4)); + ip4.sin_family= AF_INET; + memcpy(&ip4.sin_addr, arg->ptr(), IN_ADDR_SIZE); + + char ip4_string[INET_ADDRSTRLEN]; + + int err_code= vio_getnameinfo((const sockaddr *) &ip4, + ip4_string, sizeof (ip4_string), + NULL, 0, + NI_NUMERICHOST); + + if (err_code) + { + sql_print_warning("INET6_NTOA(): getnameinfo() failed with %d: %s", + err_code, gai_strerror(err_code)); + return false; + } + + buffer->length(0); + buffer->append(ip4_string, (uint32) strlen(ip4_string), &my_charset_latin1); + + return true; + } + else if (arg->length() == IN6_ADDR_SIZE) + { + sockaddr_in6 ip6; + bzero(&ip6, sizeof (ip6)); + ip6.sin6_family= AF_INET6; + memcpy(&ip6.sin6_addr, arg->ptr(), IN6_ADDR_SIZE); + + char ip6_string[INET6_ADDRSTRLEN]; + + int err_code= vio_getnameinfo((const sockaddr *) &ip6, + ip6_string, sizeof (ip6_string), + NULL, 0, + NI_NUMERICHOST); + + if (err_code) + { + sql_print_warning("INET6_NTOA(): getnameinfo() failed with %d: %s", + err_code, gai_strerror(err_code)); + return false; + } + + buffer->length(0); + buffer->append(ip6_string, (uint32) strlen(ip6_string), &my_charset_latin1); + + return true; + } + + DBUG_PRINT("info", + ("INET6_NTOA(): varbinary(4) or varbinary(16) expected.")); + return false; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Checks if the passed string represents an IPv4-address. + + @param arg The string to check. + + @return Check status. + @retval false The passed string does not represent an IPv4-address. + @retval true The passed string represents an IPv4-address. +*/ + +bool Item_func_is_ipv4::calc_value(const String *arg) +{ + in_addr ipv4_address; + + return str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address); +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Checks if the passed string represents an IPv6-address. + + @param arg The string to check. + + @return Check status. + @retval false The passed string does not represent an IPv6-address. + @retval true The passed string represents an IPv6-address. +*/ + +bool Item_func_is_ipv6::calc_value(const String *arg) +{ + in6_addr ipv6_address; + + return str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address); +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Checks if the passed IPv6-address is an IPv4-compat IPv6-address. + + @param arg The IPv6-address to check. + + @return Check status. + @retval false The passed IPv6-address is not an IPv4-compatible IPv6-address. + @retval true The passed IPv6-address is an IPv4-compatible IPv6-address. +*/ + +bool Item_func_is_ipv4_compat::calc_value(const String *arg) +{ + if (arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) + return false; + + return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) arg->ptr()); +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Checks if the passed IPv6-address is an IPv4-mapped IPv6-address. + + @param arg The IPv6-address to check. + + @return Check status. + @retval false The passed IPv6-address is not an IPv4-mapped IPv6-address. + @retval true The passed IPv6-address is an IPv4-mapped IPv6-address. +*/ + +bool Item_func_is_ipv4_mapped::calc_value(const String *arg) +{ + if (arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) + return false; + + return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) arg->ptr()); +} === modified file 'sql/item_inetfunc.h' --- a/sql/item_inetfunc.h 2011-03-29 13:25:20 +0000 +++ b/sql/item_inetfunc.h 2011-04-06 20:12:41 +0000 @@ -71,4 +71,185 @@ public: } }; + +/************************************************************************* + Item_func_inet_bool_base implements common code for INET6/IP-related + functions returning boolean value. +*************************************************************************/ + +class Item_func_inet_bool_base : public Item_bool_func +{ +public: + inline Item_func_inet_bool_base(Item *ip_addr) + : Item_bool_func(ip_addr) + { + null_value= false; + } + +public: + virtual longlong val_int(); + +protected: + virtual bool calc_value(const String *arg) = 0; +}; + + +/************************************************************************* + Item_func_inet_bool_base implements common code for INET6/IP-related + functions returning string value. +*************************************************************************/ + +class Item_func_inet_str_base : public Item_str_ascii_func +{ +public: + inline Item_func_inet_str_base(Item *arg) + : Item_str_ascii_func(arg) + { } + +public: + virtual String *val_str_ascii(String *buffer); + +protected: + virtual bool calc_value(String *arg, String *buffer) = 0; +}; + + +/************************************************************************* + Item_func_inet6_aton implements INET6_ATON() SQL-function. +*************************************************************************/ + +class Item_func_inet6_aton : public Item_func_inet_str_base +{ +public: + inline Item_func_inet6_aton(Item *ip_addr) + : Item_func_inet_str_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "inet6_aton"; } + + virtual void fix_length_and_dec() + { + decimals= 0; + fix_length_and_charset(16, &my_charset_bin); + maybe_null= 1; + } + +protected: + virtual bool calc_value(String *arg, String *buffer); +}; + + +/************************************************************************* + Item_func_inet6_ntoa implements INET6_NTOA() SQL-function. +*************************************************************************/ + +class Item_func_inet6_ntoa : public Item_func_inet_str_base +{ +public: + inline Item_func_inet6_ntoa(Item *ip_addr) + : Item_func_inet_str_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "inet6_ntoa"; } + + virtual void fix_length_and_dec() + { + decimals= 0; + + // max length: IPv6-address -- 16 bytes + // 16 bytes / 2 bytes per group == 8 groups => 7 delimiter + // 4 symbols per group + fix_length_and_charset(8 * 4 + 7, default_charset()); + + maybe_null= 1; + } + +protected: + virtual bool calc_value(String *arg, String *buffer); +}; + + +/************************************************************************* + Item_func_is_ipv4 implements IS_IPV4() SQL-function. +*************************************************************************/ + +class Item_func_is_ipv4 : public Item_func_inet_bool_base +{ +public: + inline Item_func_is_ipv4(Item *ip_addr) + : Item_func_inet_bool_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "is_ipv4"; } + +protected: + virtual bool calc_value(const String *arg); +}; + + +/************************************************************************* + Item_func_is_ipv6 implements IS_IPV6() SQL-function. +*************************************************************************/ + +class Item_func_is_ipv6 : public Item_func_inet_bool_base +{ +public: + inline Item_func_is_ipv6(Item *ip_addr) + : Item_func_inet_bool_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "is_ipv6"; } + +protected: + virtual bool calc_value(const String *arg); +}; + + +/************************************************************************* + Item_func_is_ipv4_compat implements IS_IPV4_COMPAT() SQL-function. +*************************************************************************/ + +class Item_func_is_ipv4_compat : public Item_func_inet_bool_base +{ +public: + inline Item_func_is_ipv4_compat(Item *ip_addr) + : Item_func_inet_bool_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "is_ipv4_compat"; } + +protected: + virtual bool calc_value(const String *arg); +}; + + +/************************************************************************* + Item_func_is_ipv4_mapped implements IS_IPV4_MAPPED() SQL-function. +*************************************************************************/ + +class Item_func_is_ipv4_mapped : public Item_func_inet_bool_base +{ +public: + inline Item_func_is_ipv4_mapped(Item *ip_addr) + : Item_func_inet_bool_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "is_ipv4_mapped"; } + +protected: + virtual bool calc_value(const String *arg); +}; + #endif // ITEM_INETFUNC_INCLUDED --===============7331141103821098764== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/alexander.nozdrin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alexander.nozdrin@stripped\ # brsjbaci13k3ro0h # target_branch: file:///home/alik/MySQL/bzr/00/wl5787/mysql-trunk-\ # wl5787/ # testament_sha1: 3a0c4a905b916a3396014dd72af06555b25ea790 # timestamp: 2011-04-07 00:12:46 +0400 # base_revision_id: alexander.nozdrin@stripped\ # 96ecwskvyzk8y2pp # # Begin bundle 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 --===============7331141103821098764==--