From 2c7c7e121634deb8a1c90a61ea08f34f9123789e Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 14 May 2026 00:17:24 +0400 Subject: [PATCH] MDEV-39573 Server crashes in Item_char_typecast::fix_length_and_dec_internal after select xmltype. Charset specified for XMLTYPE constructor. Error returned if XML is in UTF16/UTF32 as we can't parse it yet. XML check added so only well-formed allowed. --- .../type_xmltype/type_xmltype.result | 19 +++++++++++++ .../mysql-test/type_xmltype/type_xmltype.test | 15 ++++++++++ plugin/type_xmltype/sql_type_xmltype.cc | 28 ++++++++++++++++++- plugin/type_xmltype/sql_type_xmltype.h | 1 + 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.result b/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.result index cd75e8e1462..0825d7f35d6 100644 --- a/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.result +++ b/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.result @@ -279,4 +279,23 @@ INSERT INTO t1 SELECT 'a'; ERROR HY000: Incorrect XMLTYPE value: 'a' DROP TABLE t1; set sql_mode= DEFAULT; +# +# MDEV-39573 Server crashes in Item_char_typecast::fix_length_and_dec_internal after select xmltype +# +SELECT XMLTYPE(1); +XMLTYPE(1) +NULL +SELECT XMLTYPE(""); +XMLTYPE("") + +SELECT CAST(1 AS XMLTYPE); +CAST(1 AS XMLTYPE) +NULL +SELECT CAST("" AS XMLTYPE); +CAST("" AS XMLTYPE) + +SELECT CAST(1 AS XMLTYPE CHARSET utf32); +ERROR 42000: This version of MariaDB doesn't yet support 'CAST(AS XMLTYPE CHARACTER SET ucs2/utf16/utf32)' +SELECT CAST("" AS XMLTYPE CHARSET utf32); +ERROR 42000: This version of MariaDB doesn't yet support 'CAST(AS XMLTYPE CHARACTER SET ucs2/utf16/utf32)' # End of 12.3 tests diff --git a/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.test b/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.test index f23e02d7cc8..573533e00ce 100644 --- a/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.test +++ b/plugin/type_xmltype/mysql-test/type_xmltype/type_xmltype.test @@ -220,4 +220,19 @@ INSERT INTO t1 SELECT 'a'; DROP TABLE t1; set sql_mode= DEFAULT; +--echo # +--echo # MDEV-39573 Server crashes in Item_char_typecast::fix_length_and_dec_internal after select xmltype +--echo # + +SELECT XMLTYPE(1); +SELECT XMLTYPE(""); + +SELECT CAST(1 AS XMLTYPE); +SELECT CAST("" AS XMLTYPE); + +--error ER_NOT_SUPPORTED_YET +SELECT CAST(1 AS XMLTYPE CHARSET utf32); +--error ER_NOT_SUPPORTED_YET +SELECT CAST("" AS XMLTYPE CHARSET utf32); + --echo # End of 12.3 tests diff --git a/plugin/type_xmltype/sql_type_xmltype.cc b/plugin/type_xmltype/sql_type_xmltype.cc index d54bb5888f8..4aaa68a96d6 100644 --- a/plugin/type_xmltype/sql_type_xmltype.cc +++ b/plugin/type_xmltype/sql_type_xmltype.cc @@ -145,7 +145,8 @@ Type_handler_xmltype::make_constructor_item(THD *thd, List *args) const return NULL; Item_args tmp(thd, *args); return new (thd->mem_root) - Item_xmltype_typecast(thd, tmp.arguments()[0], NULL); + Item_xmltype_typecast(thd, tmp.arguments()[0], + thd->variables.collation_connection); } @@ -281,9 +282,34 @@ bool Item_xmltype_typecast::fix_length_and_dec(THD *thd) { Item_char_typecast::fix_length_and_dec_str(); set_func_handler(&item_xmltype_typecast_func_handler); + + if (cast_charset()->mbminlen > 1) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "CAST(AS XMLTYPE CHARACTER SET ucs2/utf16/utf32)"); + return true; + } + return false; } + +String *Item_xmltype_typecast::val_str(String *to) +{ + String *res= Item_char_typecast::val_str(to); + if (!res) + return NULL; + + if (check_parse_xml(res->ptr(), res->length(), res->charset()) != MY_XML_OK) + { + null_value= TRUE; + return NULL; + } + + return res; +} + + void Item_xmltype_typecast::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); diff --git a/plugin/type_xmltype/sql_type_xmltype.h b/plugin/type_xmltype/sql_type_xmltype.h index d7841e9d834..c393c24caa9 100644 --- a/plugin/type_xmltype/sql_type_xmltype.h +++ b/plugin/type_xmltype/sql_type_xmltype.h @@ -140,6 +140,7 @@ public: return name; } bool fix_length_and_dec(THD *thd) override; + String *val_str(String *to) override; Item *shallow_copy(THD *thd) const override { return get_item_copy(thd, this); }