From: Alexander Nozdrin Date: March 29 2011 1:32pm Subject: bzr commit into mysql-trunk branch (alexander.nozdrin:3330) WL#5787 List-Archive: http://lists.mysql.com/commits/134167 Message-Id: <201103291332.p2TDWBAx003323@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6877960639062603831==" --===============6877960639062603831== 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 3330 Alexander Nozdrin 2011-03-29 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() - MAKE_IPV4_COMPAT() - MAKE_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-03-29 13:32:03 +0000 @@ -400,6 +400,513 @@ 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); +INET6_ATON(NULL) +NULL +SELECT INET6_ATON(123); +INET6_ATON(123) +NULL +SELECT INET6_ATON(123.45); +INET6_ATON(123.45) +NULL +SELECT INET6_ATON(NOW()); +INET6_ATON(NOW()) +NULL +SELECT INET6_ATON('1.2.3'); +INET6_ATON('1.2.3') +NULL +SELECT INET6_ATON('1.2.3.'); +INET6_ATON('1.2.3.') +NULL +SELECT INET6_ATON('1..3.4'); +INET6_ATON('1..3.4') +NULL +SELECT INET6_ATON('-1.2.3.4'); +INET6_ATON('-1.2.3.4') +NULL +SELECT INET6_ATON('1.2.3.256'); +INET6_ATON('1.2.3.256') +NULL +SELECT INET6_ATON('1.2.3.4.5'); +INET6_ATON('1.2.3.4.5') +NULL +SELECT INET6_ATON('0001.2.3.4'); +INET6_ATON('0001.2.3.4') +NULL +SELECT INET6_ATON('0x1.2.3.4'); +INET6_ATON('0x1.2.3.4') +NULL +SELECT INET6_ATON('a.2.3.4'); +INET6_ATON('a.2.3.4') +NULL +SELECT INET6_ATON('1.2.3.4:80'); +INET6_ATON('1.2.3.4:80') +NULL +SELECT INET6_ATON('1.2.3.4/32'); +INET6_ATON('1.2.3.4/32') +NULL +SELECT INET6_ATON('mysql.com'); +INET6_ATON('mysql.com') +NULL +SELECT INET6_ATON(':::'); +INET6_ATON(':::') +NULL +SELECT INET6_ATON('::c0a80102'); +INET6_ATON('::c0a80102') +NULL +SELECT INET6_ATON('1020::3040::5060'); +INET6_ATON('1020::3040::5060') +NULL +SELECT INET6_ATON('::ABCZ'); +INET6_ATON('::ABCZ') +NULL +SELECT INET6_ATON('::01.2.3.4'); +INET6_ATON('::01.2.3.4') +NULL +SELECT INET6_ATON('::1.02.3.4'); +INET6_ATON('::1.02.3.4') +NULL +SELECT INET6_ATON('::1.2.03.4'); +INET6_ATON('::1.2.03.4') +NULL +SELECT INET6_ATON('::1.2.3.04'); +INET6_ATON('::1.2.3.04') +NULL +SELECT INET6_ATON('::1.2.3.00'); +INET6_ATON('::1.2.3.00') +NULL +SELECT INET6_ATON('::0x1.2.3.4'); +INET6_ATON('::0x1.2.3.4') +NULL +SELECT INET6_ATON('::1.0x2.3.4'); +INET6_ATON('::1.0x2.3.4') +NULL +SELECT INET6_ATON('::a.b.c.d'); +INET6_ATON('::a.b.c.d') +NULL +SELECT INET6_ATON('::FFFF:01.2.3.4'); +INET6_ATON('::FFFF:01.2.3.4') +NULL +SELECT INET6_ATON('::FFFF:1.02.3.4'); +INET6_ATON('::FFFF:1.02.3.4') +NULL +SELECT INET6_ATON('::FFFF:1.2.03.4'); +INET6_ATON('::FFFF:1.2.03.4') +NULL +SELECT INET6_ATON('::FFFF:1.2.3.04'); +INET6_ATON('::FFFF:1.2.3.04') +NULL +SELECT INET6_ATON('::FFFF:1.2.3.00'); +INET6_ATON('::FFFF:1.2.3.00') +NULL +SELECT INET6_ATON('::FFFF:0x1.2.3.4'); +INET6_ATON('::FFFF:0x1.2.3.4') +NULL +SELECT INET6_ATON('::FFFF:1.0x2.3.4'); +INET6_ATON('::FFFF:1.0x2.3.4') +NULL +SELECT INET6_ATON('::FFFF:a.b.c.d'); +INET6_ATON('::FFFF:a.b.c.d') +NULL +SELECT INET6_ATON('::1.2.3.4:ABCD'); +INET6_ATON('::1.2.3.4:ABCD') +NULL +# 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 + +# -- 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') +0 +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 MAKE_IPV4_COMPAT() and MAKE_IPV4_MAPPED()... + +SELECT HEX(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +HEX(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))) +00000000000000000000000001020304 +SELECT INET6_NTOA(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +INET6_NTOA(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))) +::1.2.3.4 +SELECT IS_IPV4_COMPAT(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +IS_IPV4_COMPAT(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))) +1 +SELECT IS_IPV4_MAPPED(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +IS_IPV4_MAPPED(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))) +0 +SELECT HEX(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +HEX(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))) +00000000000000000000FFFF01020304 +SELECT INET6_NTOA(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +INET6_NTOA(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))) +::ffff:1.2.3.4 +SELECT IS_IPV4_COMPAT(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +IS_IPV4_COMPAT(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))) +0 +SELECT IS_IPV4_MAPPED(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +IS_IPV4_MAPPED(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))) +1 +SELECT INET6_NTOA(MAKE_IPV4_COMPAT('1234')); +INET6_NTOA(MAKE_IPV4_COMPAT('1234')) +NULL +SELECT INET6_NTOA(MAKE_IPV4_COMPAT(BINARY('1234'))); +INET6_NTOA(MAKE_IPV4_COMPAT(BINARY('1234'))) +::49.50.51.52 +SELECT INET6_NTOA(MAKE_IPV4_MAPPED('1234')); +INET6_NTOA(MAKE_IPV4_MAPPED('1234')) +NULL +SELECT INET6_NTOA(MAKE_IPV4_MAPPED(BINARY('1234'))); +INET6_NTOA(MAKE_IPV4_MAPPED(BINARY('1234'))) +::ffff:49.50.51.52 + +# -- 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-03-29 13:32:03 +0000 @@ -541,6 +541,279 @@ 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); +SELECT INET6_ATON(123); +SELECT INET6_ATON(123.45); +SELECT INET6_ATON(NOW()); + +SELECT INET6_ATON('1.2.3'); +SELECT INET6_ATON('1.2.3.'); +SELECT INET6_ATON('1..3.4'); +SELECT INET6_ATON('-1.2.3.4'); +SELECT INET6_ATON('1.2.3.256'); +SELECT INET6_ATON('1.2.3.4.5'); +SELECT INET6_ATON('0001.2.3.4'); +SELECT INET6_ATON('0x1.2.3.4'); +SELECT INET6_ATON('a.2.3.4'); + +SELECT INET6_ATON('1.2.3.4:80'); +SELECT INET6_ATON('1.2.3.4/32'); + +SELECT INET6_ATON('mysql.com'); + +SELECT INET6_ATON(':::'); +SELECT INET6_ATON('::c0a80102'); +SELECT INET6_ATON('1020::3040::5060'); +SELECT INET6_ATON('::ABCZ'); + +SELECT INET6_ATON('::01.2.3.4'); +SELECT INET6_ATON('::1.02.3.4'); +SELECT INET6_ATON('::1.2.03.4'); +SELECT INET6_ATON('::1.2.3.04'); +SELECT INET6_ATON('::1.2.3.00'); +SELECT INET6_ATON('::0x1.2.3.4'); +SELECT INET6_ATON('::1.0x2.3.4'); +SELECT INET6_ATON('::a.b.c.d'); + +SELECT INET6_ATON('::FFFF:01.2.3.4'); +SELECT INET6_ATON('::FFFF:1.02.3.4'); +SELECT INET6_ATON('::FFFF:1.2.03.4'); +SELECT INET6_ATON('::FFFF:1.2.3.04'); +SELECT INET6_ATON('::FFFF:1.2.3.00'); +SELECT INET6_ATON('::FFFF:0x1.2.3.4'); +SELECT INET6_ATON('::FFFF:1.0x2.3.4'); +SELECT INET6_ATON('::FFFF:a.b.c.d'); + +SELECT INET6_ATON('::1.2.3.4:ABCD'); + +--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')); + +--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 MAKE_IPV4_COMPAT() and MAKE_IPV4_MAPPED()... +--echo + +SELECT HEX(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +SELECT INET6_NTOA(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +SELECT IS_IPV4_COMPAT(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); +SELECT IS_IPV4_MAPPED(MAKE_IPV4_COMPAT(INET6_ATON('1.2.3.4'))); + +SELECT HEX(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +SELECT INET6_NTOA(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +SELECT IS_IPV4_COMPAT(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); +SELECT IS_IPV4_MAPPED(MAKE_IPV4_MAPPED(INET6_ATON('1.2.3.4'))); + +SELECT INET6_NTOA(MAKE_IPV4_COMPAT('1234')); +SELECT INET6_NTOA(MAKE_IPV4_COMPAT(BINARY('1234'))); + +SELECT INET6_NTOA(MAKE_IPV4_MAPPED('1234')); +SELECT INET6_NTOA(MAKE_IPV4_MAPPED(BINARY('1234'))); + +--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-03-29 13:32:03 +0000 @@ -1204,6 +1204,110 @@ 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_make_ipv4_compat : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_make_ipv4_compat s_singleton; + +protected: + Create_func_make_ipv4_compat() {} + virtual ~Create_func_make_ipv4_compat() {} +}; + + +class Create_func_make_ipv4_mapped : public Create_func_arg1 +{ +public: + virtual Item *create(THD *thd, Item *arg1); + + static Create_func_make_ipv4_mapped s_singleton; + +protected: + Create_func_make_ipv4_mapped() {} + virtual ~Create_func_make_ipv4_mapped() {} +}; + + class Create_func_instr : public Create_func_arg2 { public: @@ -3904,6 +4008,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 +4035,60 @@ 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_make_ipv4_compat Create_func_make_ipv4_compat::s_singleton; + +Item* +Create_func_make_ipv4_compat::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_make_ipv4_compat(arg1); +} + + +Create_func_make_ipv4_mapped Create_func_make_ipv4_mapped::s_singleton; + +Item* +Create_func_make_ipv4_mapped::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_make_ipv4_mapped(arg1); +} + + Create_func_instr Create_func_instr::s_singleton; Item* @@ -5279,6 +5455,14 @@ 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("MAKE_IPV4_COMPAT") }, BUILDER(Create_func_make_ipv4_compat)}, + { { C_STRING_WITH_LEN("MAKE_IPV4_MAPPED") }, BUILDER(Create_func_make_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-03-29 13:25:20 +0000 +++ b/sql/item_inetfunc.cc 2011-03-29 13:32:03 +0000 @@ -123,3 +123,485 @@ 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)); + return false; + } + + if (str_length > 15) + { + DBUG_PRINT("error", ("str_to_ipv4(%s): " + "invalid IPv4 address: too long.", 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 (c >= '0' && c <= '9') + { + ++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)); + 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)); + 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)); + 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)); + return false; + } + } + else + { + DBUG_PRINT("error", ("str_to_ipv4(%s): invalid IPv4 address: " + "invalid character at pos %d.", + str, (int) (p - str))); + return false; + } + } + + if (c == '.') + { + DBUG_PRINT("error", ("str_to_ipv4(%s): invalid IPv4 address: " + "ending at '.'.", str)); + return false; + } + + if (dot_count != 3) + { + DBUG_PRINT("error", ("str_to_ipv4(%s): invalid IPv4 address: " + "classful address (too few groups).", 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, 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) +{ + struct addrinfo hints; + bzero(&hints, sizeof (hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET6; + + struct addrinfo *result; + + int err_code= getaddrinfo(str, NULL, &hints, &result); + + if (err_code) + { + DBUG_PRINT("error", ("str_to_ipv6(%s): getaddrinfo() failed with %d: %s", + str, err_code, gai_strerror(err_code))); + return false; + } + + if (!result) + { + sql_print_warning("str_to_ipv6(%s): getaddrinfo() succeeded, " + "but returned NULL.", str); + return false; + } + + memcpy(ipv6_address, + &((sockaddr_in6 *) result->ai_addr)->sin6_addr, + sizeof (struct in6_addr)); + + freeaddrinfo(result); + + DBUG_PRINT("info", ("str_to_ipv6(%s): valid IPv6 address.", str)); + 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() == 4) + { + sockaddr_in ip4; + bzero(&ip4, sizeof (ip4)); + ip4.sin_family = AF_INET; + memcpy(&ip4.sin_addr, arg->ptr(), 4); + + 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, strlen(ip4_string), &my_charset_latin1); + + return true; + } + else if (arg->length() == 16) + { + sockaddr_in6 ip6; + bzero(&ip6, sizeof (ip6)); + ip6.sin6_family = AF_INET6; + memcpy(&ip6.sin6_addr, arg->ptr(), 16); + + 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, 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() != 16 || arg->charset() != &my_charset_bin) + return false; + + return IN6_IS_ADDR_V4COMPAT(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() != 16 || arg->charset() != &my_charset_bin) + return false; + + return IN6_IS_ADDR_V4MAPPED(arg->ptr()); +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Makes an IPv4-compatible IPv6-address address out of IPv4-address. + + @param arg The IPv4-address. + @param [out] buffer Buffer to store IPv6-address-data. + + @return Completion status. + @retval false The passed data does not represent an IPv4-address. + @retval true The passed IPv4-address has been converted successfully. +*/ + +bool Item_func_make_ipv4_compat::calc_value(String *arg, String *buffer) +{ + if (arg->length() != 4 || arg->charset() != &my_charset_bin) + return false; + + char ip6_bytes[16]; + + bzero(ip6_bytes, sizeof (ip6_bytes)); + ip6_bytes[12]= arg->ptr()[0]; + ip6_bytes[13]= arg->ptr()[1]; + ip6_bytes[14]= arg->ptr()[2]; + ip6_bytes[15]= arg->ptr()[3]; + + buffer->length(0); + buffer->append(ip6_bytes, 16, &my_charset_bin); + + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +/** + Makes an IPv4-mapped IPv6-address address out of IPv4-address. + + @param arg The IPv4-address. + @param [out] buffer Buffer to store IPv6-address-data. + + @return Completion status. + @retval false The passed data does not represent an IPv4-address. + @retval true The passed IPv4-address has been converted successfully. +*/ + +bool Item_func_make_ipv4_mapped::calc_value(String *arg, String *buffer) +{ + if (arg->length() != 4 || arg->charset() != &my_charset_bin) + return false; + + char ip6_bytes[16]; + + bzero(ip6_bytes, sizeof (ip6_bytes)); + ip6_bytes[10]= 0xFF; + ip6_bytes[11]= 0xFF; + ip6_bytes[12]= arg->ptr()[0]; + ip6_bytes[13]= arg->ptr()[1]; + ip6_bytes[14]= arg->ptr()[2]; + ip6_bytes[15]= arg->ptr()[3]; + + buffer->length(0); + buffer->append(ip6_bytes, 16, &my_charset_bin); + + return true; +} === modified file 'sql/item_inetfunc.h' --- a/sql/item_inetfunc.h 2011-03-29 13:25:20 +0000 +++ b/sql/item_inetfunc.h 2011-03-29 13:32:03 +0000 @@ -71,4 +71,239 @@ 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); +}; + + +/************************************************************************* + Item_func_make_ipv4_compat implements MAKE_IPV4_COMPAT() SQL-function. +*************************************************************************/ + +class Item_func_make_ipv4_compat : public Item_func_inet_str_base +{ +public: + inline Item_func_make_ipv4_compat(Item *ip_addr) + : Item_func_inet_str_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "make_ipv4_compat"; } + + 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_make_ipv4_mapped implements MAKE_IPV4_COMPAT() SQL-function. +*************************************************************************/ + +class Item_func_make_ipv4_mapped : public Item_func_inet_str_base +{ +public: + inline Item_func_make_ipv4_mapped(Item *ip_addr) + : Item_func_inet_str_base(ip_addr) + { } + +public: + virtual const char *func_name() const + { return "make_ipv4_mapped"; } + + virtual void fix_length_and_dec() + { + decimals= 0; + fix_length_and_charset(16, &my_charset_bin); + maybe_null= 1; + } + +public: + virtual bool calc_value(String *arg, String *buffer); +}; + #endif // ITEM_INETFUNC_INCLUDED --===============6877960639062603831== 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\ # qt4wbnqr252mywrw # target_branch: file:///home/alik/MySQL/bzr/00/wl5787/mysql-trunk-\ # wl5787/ # testament_sha1: 2e49eead4d22c4add660a65c7a56bb96455259d2 # timestamp: 2011-03-29 17:32:08 +0400 # base_revision_id: alexander.nozdrin@stripped\ # xpyje7whwtob7xx1 # # Begin bundle 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 yDIlQyZMf2jKj7xkNEKP/4u5IpwoSDPs1pqA --===============6877960639062603831==--