From 645884a4e0bec6c60267a91551f528ff1b35232b Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 7 Aug 2026 17:32:14 +1000 Subject: [PATCH] MDEV-40486 Length check for vector fields in CREATE TABLE ... SELECT The changes of MDEV-39558 2b6529426a7e7c65d286e093d84138be9dcc34a3 added length check assertion in Field_varstring constructors, and length check in type inference for SELECT set operations, to emit errors before reaching the assertions. That change caused an error to turn into an assertion failure in a separate path, when the length limit violation is not detected before tripping the assertion. So in this patch we fix it by adding an earlier length check in that path. The reason that we place this check inside Item_func_vec_fromtext::fix_length_and_dec rather than say `create_field_for_create_select is for consistency: If create table t1 as select vec_fromtext(concat('[',group_concat(1),']')) as c1 from seq_1_to_64; fails due to length limit violation, then so should create table t1 (v vector(64) not null); insert into t1 select vec_fromtext(concat('[',group_concat(1),']')) from seq_1_to_64; Also use max_char_length() instead of max_length. This is a more accurate length of characters. And add handling of empty string edge case. Added testcases accordingly. The change that uses max_char_length() causes side effects where creating a table using a VEC_FROMTEXT(CHAR(1)) would result in a 0-dimensional vector field. This is accurate but 0-dim vector table fields should not be allowed. So we add a check for that too, as well as an exception of (?) prepared statement placeholders. Also fixed the underflow in (args[0]->max_length - 1) * 2 when the arg's max length is 0. Previously this underflow would cause create table t1 select vec_fromtext(NULL) to fail with ER_TOO_BIG_FIELDLENGTH. Now the zero length check would cause it to fail with a different error (ER_WRONG_ARGUMENTS). --- mysql-test/main/vector2.result | 94 +++++++++++++++++++++++++++- mysql-test/main/vector2.test | 97 ++++++++++++++++++++++++++++- mysql-test/main/vector_funcs.result | 3 +- mysql-test/main/vector_funcs.test | 1 + sql/item_vectorfunc.cc | 19 +++++- 5 files changed, 207 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/vector2.result b/mysql-test/main/vector2.result index 5dbe71c8adf1b..9be4ffa3e5a51 100644 --- a/mysql-test/main/vector2.result +++ b/mysql-test/main/vector2.result @@ -160,7 +160,7 @@ drop table t; # MDEV-35141 Server crashes in Field_vector::report_wrong_value upon statistic collection # create table t1 (v vector(64) not null); -insert into t1 select vec_fromtext(concat('[',group_concat(1),']')) from seq_1_to_64; +insert into t1 select vec_fromtext(cast(concat('[',group_concat(1),']') as char(130))) from seq_1_to_64; analyze table t1 persistent for all; Table Op Msg_type Msg_text test.t1 analyze status Engine-independent statistics collected @@ -565,4 +565,96 @@ tmp CREATE TABLE `tmp` ( c drop table tmp, t1, t2; set sql_mode=@old_sql_mode; +# +# MDEV-40486 ER_TOO_BIG_FIELDLENGTH or assertion failure upon creating vector from blob +# +## Original testcase +CREATE TABLE t (a TEXT) AS SELECT '[1]' AS a; +CREATE TABLE tt AS SELECT VEC_FROMTEXT(a) AS f FROM t; +ERROR 42000: Column length too big for column 'f' (max = 16383); use BLOB or TEXT instead +DROP TABLE t; +## Another case, which would have failed with ERROR 1292 +## without the fix +CREATE TABLE t SELECT VEC_FROMTEXT('[1]'); +DROP TABLE t; +## Conversion from max varchar length +CREATE TABLE t (a VARCHAR(16383)) AS +SELECT concat('[1', repeat(',1', 8190), ']') AS a; +CREATE TABLE tt AS SELECT VEC_FROMTEXT(a) AS f FROM t; +DROP TABLE t,tt; +## Conversion to max vector dimension +CREATE TABLE tt AS +SELECT VEC_FROMTEXT(concat('[1', repeat(',1', 16382), ']')) AS f; +DROP TABLE tt; +CREATE TABLE tt AS +SELECT VEC_FROMTEXT(concat('[1', repeat(',1', 16383), ']')) AS f; +ERROR 42000: Column length too big for column 'f' (max = 16383); use BLOB or TEXT instead +## Zero length: no underflow and not allowed for table creation +SELECT VEC_FROMTEXT('[]') as f; +f + +CREATE TABLE t1 SELECT VEC_FROMTEXT('[]'); +ERROR 22007: Incorrect vector value: '' for column `test`.`t1`.`VEC_FROMTEXT('[]')` at row 1 +SELECT VEC_FROMTEXT('') AS f; +ERROR HY000: Incorrect arguments to VEC_FromText +CREATE TABLE tt AS SELECT VEC_FROMTEXT('') AS f; +ERROR HY000: Incorrect arguments to VEC_FromText +CREATE TABLE t1 (a CHAR(1)); +CREATE TABLE t2 AS SELECT VEC_FROMTEXT(a) AS f FROM t1; +ERROR HY000: Incorrect arguments to VEC_FromText +DROP TABLE t1; +CREATE TABLE t3 (f VECTOR(0)); +ERROR 42000: Incorrect column specifier for column 'f' +## Fails because concat('[',group_concat(1),']') is mediumblob +create view v1 as select vec_fromtext(concat('[',group_concat(1),']')) from seq_1_to_64; +ERROR 42000: Column length too big for column 'vec_fromtext(concat('[',group_concat(1),']'))' (max = 16383); use BLOB or TEXT instead +## NULLs +select vec_fromtext(NULL); +ERROR HY000: Incorrect arguments to VEC_FromText +select vec_fromtext(NULL + NULL); +vec_fromtext(NULL + NULL) +NULL +create table t1 select vec_fromtext(NULL) as c; +ERROR HY000: Incorrect arguments to VEC_FromText +create table t1 select vec_fromtext(NULL + NULL) as c; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` vector(8) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +drop table t1; +create table t1 select vec_fromtext(c) from (select '[1,2]' as c) d; +DROP TABLE t1; +create table t1 select vec_fromtext(c) from (select '' as c) d; +ERROR HY000: Incorrect arguments to VEC_FromText +create table t1 select vec_fromtext(c) from (select NULL as c) d; +ERROR HY000: Incorrect arguments to VEC_FromText +create table t2 (c varchar(5)); +insert into t2 values (NULL); +create table t1 select vec_fromtext(c) from t2; +drop table t1, t2; +## Prepared statements with placeholders +prepare p1 from 'select vec_fromtext(?)'; +execute p1 using '[1,2]'; +execute p1 using NULL; +ERROR HY000: Incorrect arguments to VEC_FromText +execute p1 using '[]'; +vec_fromtext(?) + +deallocate prepare p1; +prepare p1 from 'create table t1 select vec_fromtext(?)'; +execute p1 using '[1,2]'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `vec_fromtext(?)` vector(2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +DROP TABLE t1; +execute p1 using NULL; +ERROR HY000: Incorrect arguments to VEC_FromText +execute p1 using '[]'; +ERROR 22007: Incorrect vector value: '' for column `test`.`t1`.`vec_fromtext(?)` at row 1 +execute p1 using ''; +ERROR HY000: Incorrect arguments to VEC_FromText +deallocate prepare p1; # End of 11.8 tests diff --git a/mysql-test/main/vector2.test b/mysql-test/main/vector2.test index be2493011aacd..edf35bac3ef95 100644 --- a/mysql-test/main/vector2.test +++ b/mysql-test/main/vector2.test @@ -125,7 +125,7 @@ drop table t; --echo # MDEV-35141 Server crashes in Field_vector::report_wrong_value upon statistic collection --echo # create table t1 (v vector(64) not null); -insert into t1 select vec_fromtext(concat('[',group_concat(1),']')) from seq_1_to_64; +insert into t1 select vec_fromtext(cast(concat('[',group_concat(1),']') as char(130))) from seq_1_to_64; analyze table t1 persistent for all; drop table t1; @@ -447,4 +447,99 @@ drop table tmp, t1, t2; set sql_mode=@old_sql_mode; +--echo # +--echo # MDEV-40486 ER_TOO_BIG_FIELDLENGTH or assertion failure upon creating vector from blob +--echo # + +--echo ## Original testcase +CREATE TABLE t (a TEXT) AS SELECT '[1]' AS a; +--error ER_TOO_BIG_FIELDLENGTH +CREATE TABLE tt AS SELECT VEC_FROMTEXT(a) AS f FROM t; +DROP TABLE t; + +--echo ## Another case, which would have failed with ERROR 1292 +--echo ## without the fix +CREATE TABLE t SELECT VEC_FROMTEXT('[1]'); +DROP TABLE t; + +--echo ## Conversion from max varchar length +CREATE TABLE t (a VARCHAR(16383)) AS + SELECT concat('[1', repeat(',1', 8190), ']') AS a; +CREATE TABLE tt AS SELECT VEC_FROMTEXT(a) AS f FROM t; +DROP TABLE t,tt; + +--echo ## Conversion to max vector dimension +CREATE TABLE tt AS + SELECT VEC_FROMTEXT(concat('[1', repeat(',1', 16382), ']')) AS f; +DROP TABLE tt; + +--error ER_TOO_BIG_FIELDLENGTH +CREATE TABLE tt AS + SELECT VEC_FROMTEXT(concat('[1', repeat(',1', 16383), ']')) AS f; + +--echo ## Zero length: no underflow and not allowed for table creation +SELECT VEC_FROMTEXT('[]') as f; +--error ER_TRUNCATED_WRONG_VALUE +CREATE TABLE t1 SELECT VEC_FROMTEXT('[]'); +--error ER_WRONG_ARGUMENTS +SELECT VEC_FROMTEXT('') AS f; +--error ER_WRONG_ARGUMENTS +CREATE TABLE tt AS SELECT VEC_FROMTEXT('') AS f; + +CREATE TABLE t1 (a CHAR(1)); +--error ER_WRONG_ARGUMENTS +CREATE TABLE t2 AS SELECT VEC_FROMTEXT(a) AS f FROM t1; +DROP TABLE t1; + +--error ER_WRONG_FIELD_SPEC +CREATE TABLE t3 (f VECTOR(0)); + +--echo ## Fails because concat('[',group_concat(1),']') is mediumblob +--error ER_TOO_BIG_FIELDLENGTH +create view v1 as select vec_fromtext(concat('[',group_concat(1),']')) from seq_1_to_64; + +--echo ## NULLs +--error ER_WRONG_ARGUMENTS +select vec_fromtext(NULL); +select vec_fromtext(NULL + NULL); +--error ER_WRONG_ARGUMENTS +create table t1 select vec_fromtext(NULL) as c; +create table t1 select vec_fromtext(NULL + NULL) as c; +show create table t1; +drop table t1; + +create table t1 select vec_fromtext(c) from (select '[1,2]' as c) d; +DROP TABLE t1; +--error ER_WRONG_ARGUMENTS +create table t1 select vec_fromtext(c) from (select '' as c) d; +--error ER_WRONG_ARGUMENTS +create table t1 select vec_fromtext(c) from (select NULL as c) d; + +create table t2 (c varchar(5)); +insert into t2 values (NULL); +create table t1 select vec_fromtext(c) from t2; +drop table t1, t2; + +--echo ## Prepared statements with placeholders +prepare p1 from 'select vec_fromtext(?)'; +--disable_result_log +execute p1 using '[1,2]'; +--enable_result_log +--error ER_WRONG_ARGUMENTS +execute p1 using NULL; +execute p1 using '[]'; +deallocate prepare p1; + +prepare p1 from 'create table t1 select vec_fromtext(?)'; +execute p1 using '[1,2]'; +show create table t1; +DROP TABLE t1; +--error ER_WRONG_ARGUMENTS +execute p1 using NULL; +--error ER_TRUNCATED_WRONG_VALUE +execute p1 using '[]'; +--error ER_WRONG_ARGUMENTS +execute p1 using ''; +deallocate prepare p1; + --echo # End of 11.8 tests diff --git a/mysql-test/main/vector_funcs.result b/mysql-test/main/vector_funcs.result index 6aba9df0b055c..a609893f4bdd0 100644 --- a/mysql-test/main/vector_funcs.result +++ b/mysql-test/main/vector_funcs.result @@ -119,8 +119,7 @@ drop table t1; # MDEV-35212 Server crashes in Item_func_vec_fromtext::val_str upon query from empty table # select vec_fromtext(NULL); -vec_fromtext(NULL) -NULL +ERROR HY000: Incorrect arguments to VEC_FromText # # MDEV-35210 Vector type cannot store values which VEC_FromText produces and VEC_ToText accepts # diff --git a/mysql-test/main/vector_funcs.test b/mysql-test/main/vector_funcs.test index b0ada0fa61fbf..3bcad70535dc6 100644 --- a/mysql-test/main/vector_funcs.test +++ b/mysql-test/main/vector_funcs.test @@ -49,6 +49,7 @@ drop table t1; --echo # --echo # MDEV-35212 Server crashes in Item_func_vec_fromtext::val_str upon query from empty table --echo # +--error ER_WRONG_ARGUMENTS select vec_fromtext(NULL); --echo # diff --git a/sql/item_vectorfunc.cc b/sql/item_vectorfunc.cc index 13e458d7675d6..ad1b9e24a904b 100644 --- a/sql/item_vectorfunc.cc +++ b/sql/item_vectorfunc.cc @@ -181,12 +181,25 @@ Item_func_vec_fromtext::Item_func_vec_fromtext(THD *thd, Item *a) bool Item_func_vec_fromtext::fix_length_and_dec(THD *thd) { + uint maxlen= args[0]->max_char_length(); decimals= 0; /* Worst case scenario, for a valid input we have a string of the form: [1,2,3,4,5,...] single digit numbers. - This means we can have (max_length - 1) / 2 floats. - Each float takes 4 bytes, so we do (max_length - 1) * 2. */ - fix_length_and_charset((args[0]->max_length - 1) * 2, &my_charset_bin); + This means we can have (maxlen - 1) / 2 floats. + Each float takes 4 bytes, so we do (maxlen - 1) * 2. */ + fix_length_and_charset(maxlen ? (maxlen - 1) * 2 : 0, &my_charset_bin); + /* Zero-length vectors are not allowed to be table fields */ + if (max_length == 0 && args[0]->type() != PARAM_ITEM) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name()); + return true; + } + if (max_length > MAX_FIELD_VARCHARLENGTH) + { + my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), name.str, + static_cast(MAX_FIELD_VARCHARLENGTH / sizeof(float))); + return true; + } set_maybe_null(); return false; }