From 312ba3cc3dd13fe3da1aeac8a32887be98c8a7ae Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 10 Oct 2019 08:12:14 +0400 Subject: [PATCH] MDEV-20783 INET6 cannot be converted to BINARY(16) --- .../mysql-test/type_inet/type_inet6.result | 118 ++++++++++++++++++ .../mysql-test/type_inet/type_inet6.test | 114 +++++++++++++++++ plugin/type_inet/sql_type_inet.cc | 50 +++++--- sql/field.h | 5 + sql/field_conv.cc | 6 +- 5 files changed, 271 insertions(+), 22 deletions(-) diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.result b/plugin/type_inet/mysql-test/type_inet/type_inet6.result index b402e1cae2a12..3e5905cecec86 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.result @@ -1266,6 +1266,16 @@ Warning 1292 Incorrect inet6 value: '::192.168.0.1' Warning 1292 Incorrect inet6 value: '::ffff:192.168.0.1' DROP TABLE t1; # +# ALTER from INET6 to INET6 +# +CREATE TABLE t1 (a INET6, b INT); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329', 1); +ALTER TABLE t1 MODIFY b DECIMAL(10,2); +SELECT * FROM t1; +a b +2001:db8::ff00:42:8329 1.00 +DROP TABLE t1; +# # ALTER to character string data types # CREATE OR REPLACE TABLE t1 (a INET6); @@ -1377,6 +1387,104 @@ a 2001:db8::ff00:42:8329 DROP TABLE t1; # +# ALTER to binary string data types +# +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(16); +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(17); +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF000042832900 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(15); +ERROR 22001: Data too long for column 'a' at row 1 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a TINYBLOB; +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BLOB; +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a MEDIUMBLOB; +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a LONGBLOB; +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; +# +# ALTER from binary string data types +# +CREATE TABLE t1 (a BINARY(16)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +a +2001:db8::ff00:42:8329 +DROP TABLE t1; +CREATE TABLE t1 (a BINARY(17)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF000042832900'); +ALTER TABLE t1 MODIFY a INET6; +ERROR 22007: Incorrect inet6 value: ' \x01\x0D\xB8\x00\x00\x00\x00\x00\x00\xFF\x00\x00B\x83)\x00' for column `test`.`t1`.`a` at row 1 +DROP TABLE t1; +CREATE TABLE t1 (a BINARY(15)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF00004283'); +ALTER TABLE t1 MODIFY a INET6; +ERROR 22007: Incorrect inet6 value: ' \x01\x0D\xB8\x00\x00\x00\x00\x00\x00\xFF\x00\x00B\x83' for column `test`.`t1`.`a` at row 1 +DROP TABLE t1; +CREATE TABLE t1 (a TINYBLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +a +2001:db8::ff00:42:8329 +DROP TABLE t1; +CREATE TABLE t1 (a BLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +a +2001:db8::ff00:42:8329 +DROP TABLE t1; +CREATE TABLE t1 (a MEDIUMBLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +a +2001:db8::ff00:42:8329 +DROP TABLE t1; +CREATE TABLE t1 (a BLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +a +2001:db8::ff00:42:8329 +DROP TABLE t1; +# # Limit clause parameter # TODO: this should fail. # The test for a valid data type should be moved @@ -1398,3 +1506,13 @@ SELECT * FROM t1; a 2001:db8::ff00:42:8329 DROP TABLE t1; +# +# MDEV-20783 INET6 cannot be converted to BINARY(16) (requires clarification in documentation) +# +CREATE OR REPLACE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(16); +SELECT HEX(a) FROM t1; +HEX(a) +20010DB8000000000000FF0000428329 +DROP TABLE t1; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.test b/plugin/type_inet/mysql-test/type_inet/type_inet6.test index 2abcb2a9fc560..03b83214edc4c 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.test +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.test @@ -814,6 +814,16 @@ SELECT id, length(a), a, IS_IPV4_COMPAT(BINARY a) FROM t1 ORDER BY id; DROP TABLE t1; +--echo # +--echo # ALTER from INET6 to INET6 +--echo # + +CREATE TABLE t1 (a INET6, b INT); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329', 1); +ALTER TABLE t1 MODIFY b DECIMAL(10,2); +SELECT * FROM t1; +DROP TABLE t1; + --echo # --echo # ALTER to character string data types --echo # @@ -903,6 +913,100 @@ SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # ALTER to binary string data types +--echo # + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(16); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(17); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +--error ER_DATA_TOO_LONG +ALTER TABLE t1 MODIFY a BINARY(15); +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a TINYBLOB; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BLOB; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a MEDIUMBLOB; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a LONGBLOB; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + + +--echo # +--echo # ALTER from binary string data types +--echo # + +CREATE TABLE t1 (a BINARY(16)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a BINARY(17)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF000042832900'); +--error ER_TRUNCATED_WRONG_VALUE +ALTER TABLE t1 MODIFY a INET6; +DROP TABLE t1; + +CREATE TABLE t1 (a BINARY(15)); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF00004283'); +--error ER_TRUNCATED_WRONG_VALUE +ALTER TABLE t1 MODIFY a INET6; +DROP TABLE t1; + +CREATE TABLE t1 (a TINYBLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a BLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a MEDIUMBLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a BLOB); +INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329'); +ALTER TABLE t1 MODIFY a INET6; +SELECT a FROM t1; +DROP TABLE t1; + + --echo # --echo # Limit clause parameter --echo # TODO: this should fail. @@ -935,3 +1039,13 @@ SELECT CAST(a AS CHAR(39)) FROM t1; ALTER TABLE t1 MODIFY a CHAR(39); SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # MDEV-20783 INET6 cannot be converted to BINARY(16) (requires clarification in documentation) +--echo # + +CREATE OR REPLACE TABLE t1 (a INET6); +INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329'); +ALTER TABLE t1 MODIFY a BINARY(16); +SELECT HEX(a) FROM t1; +DROP TABLE t1; diff --git a/plugin/type_inet/sql_type_inet.cc b/plugin/type_inet/sql_type_inet.cc index 4cd104af20650..0c50cfe034c38 100644 --- a/plugin/type_inet/sql_type_inet.cc +++ b/plugin/type_inet/sql_type_inet.cc @@ -823,26 +823,38 @@ class Field_inet6: public Field Copy_func *get_copy_func(const Field *from) const override { // ALTER to INET6 from another field - /* - if (eq_def(from)) - return get_identical_copy_func(); - switch (from->cmp_type()) { - case STRING_RESULT: - return do_field_string; - case TIME_RESULT: - return do_field_temporal; - case DECIMAL_RESULT: - return do_field_decimal; - case REAL_RESULT: - return do_field_real; - case INT_RESULT: - return do_field_int; - case ROW_RESULT: - DBUG_ASSERT(0); - break; + return do_field_string; + } + + Copy_func *get_copy_func_to(const Field *to) const override + { + if (type_handler() == to->type_handler()) + { + // ALTER from INET6 to INET6 + DBUG_ASSERT(pack_length() == to->pack_length()); + DBUG_ASSERT(charset() == to->charset()); + DBUG_ASSERT(sort_charset() == to->sort_charset()); + return Field::do_field_eq; } - */ - return do_field_string;//QQ + // ALTER from INET6 to another data type + if (to->charset() == &my_charset_bin && + dynamic_cast + (to->type_handler())) + { + /* + ALTER from INET6 to a binary string type, e.g.: + BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB + */ + return do_field_inet6_native_to_binary; + } + return do_field_string; + } + + static void do_field_inet6_native_to_binary(Copy_field *copy) + { + NativeBufferInet6 res; + copy->from_field->val_native(&res); + copy->to_field->store(res.ptr(), res.length(), &my_charset_bin); } bool memcpy_field_possible(const Field *from) const override diff --git a/sql/field.h b/sql/field.h index 9c98ea810f6ae..a0d8476df94a8 100644 --- a/sql/field.h +++ b/sql/field.h @@ -742,6 +742,7 @@ class Field: public Value_source } void error_generated_column_function_is_not_allowed(THD *thd, bool error) const; + static void do_field_eq(Copy_field *copy); static void do_field_int(Copy_field *copy); static void do_field_real(Copy_field *copy); static void do_field_string(Copy_field *copy); @@ -893,6 +894,10 @@ class Field: public Value_source */ typedef void Copy_func(Copy_field*); virtual Copy_func *get_copy_func(const Field *from) const= 0; + virtual Copy_func *get_copy_func_to(const Field *to) const + { + return to->get_copy_func(this); + } /* Store functions returns 1 on overflow and -1 on fatal error */ virtual int store_field(Field *from) { return from->save_in_field(this); } virtual int save_in_field(Field *to)= 0; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index f96c6742ea736..f975597cf70fb 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -30,7 +30,7 @@ #include "sql_class.h" // THD #include -static void do_field_eq(Copy_field *copy) +void Field::do_field_eq(Copy_field *copy) { memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); } @@ -638,7 +638,7 @@ void Copy_field::set(uchar *to,Field *from) else { to_null_ptr= 0; // For easy debugging - do_copy= do_field_eq; + do_copy= Field::do_field_eq; } } @@ -719,7 +719,7 @@ void Copy_field::set(Field *to,Field *from,bool save) if ((to->flags & BLOB_FLAG) && save) do_copy2= do_save_blob; else - do_copy2= to->get_copy_func(from); + do_copy2= from->get_copy_func_to(to); if (!do_copy) // Not null do_copy=do_copy2; }