diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-27 09:48:22 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-27 09:48:22 +0300 |
commit | 44f9736e0b5608920199e3f51cfa72b597a88e4f (patch) | |
tree | 2b622a29f6ba3916d6ef7534b28ac2be1d1f80d4 /sql/item.cc | |
parent | 49098bfd4908ff3a33ae6c6a30c2a9b7dd90e4df (diff) | |
parent | 05a0eae335ebdd1f9ac7540c263b870a17d69b9f (diff) | |
download | mariadb-git-44f9736e0b5608920199e3f51cfa72b597a88e4f.tar.gz |
Merge 10.4 into 10.5st-10.5-merge
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 96 |
1 files changed, 76 insertions, 20 deletions
diff --git a/sql/item.cc b/sql/item.cc index 2f9f6a25a7e..c661722ead4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1119,6 +1119,80 @@ bool Item::check_type_scalar(const char *opname) const } +extern "C" { + +/* + All values greater than MY_NAME_BINARY_VALUE are + interpreted as binary bytes. + The exact constant value does not matter, + but it must be greater than 0x10FFFF, + which is the maximum possible character in Unicode. +*/ +#define MY_NAME_BINARY_VALUE 0x200000 + +/* + Print all binary bytes as well as zero character U+0000 in hex notation. + Print other characters normally. +*/ +static int +my_wc_mb_item_name(CHARSET_INFO *cs, my_wc_t wc, uchar *str, uchar *end) +{ + if (wc == 0 || wc >= MY_NAME_BINARY_VALUE) + { + if (str + 4 >= end) + return MY_CS_TOOSMALL3; + str[0]= '\\'; + str[1]= 'x'; + str[2]= _dig_vec_upper[(uchar) (wc >> 4)]; + str[3]= _dig_vec_upper[(uchar) wc & 0x0F]; + return 4; + } + return my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end); +} + + +/* + Scan characters and mark all illegal sequences as binary byte values, + to have my_wc_mb_utf8_escape_name() print them using HEX notation. +*/ +static int +my_mb_wc_item_name(CHARSET_INFO *cs, my_wc_t *pwc, + const uchar *str, const uchar *end) +{ + int rc= cs->cset->mb_wc(cs, pwc, str, end); + if (rc == MY_CS_ILSEQ) + { + *pwc= MY_NAME_BINARY_VALUE + *str; + return 1; + } + return rc; +} + +} + + +static LEX_CSTRING +make_name(THD *thd, + const char *str, size_t length, CHARSET_INFO *cs, + size_t max_octet_length) +{ + uint errors; + size_t dst_nbytes= length * system_charset_info->mbmaxlen; + set_if_smaller(dst_nbytes, max_octet_length); + char *dst= (char*) thd->alloc(dst_nbytes + 1); + if (!dst) + return null_clex_str; + uint32 cnv_length= my_convert_using_func(dst, dst_nbytes, system_charset_info, + my_wc_mb_item_name, + str, length, + cs == &my_charset_bin ? + system_charset_info : cs, + my_mb_wc_item_name, &errors); + dst[cnv_length]= '\0'; + return Lex_cstring(dst, cnv_length); +} + + void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs) { if (!length) @@ -1169,32 +1243,14 @@ void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs) ER_REMOVED_SPACES, ER_THD(thd, ER_REMOVED_SPACES), buff); } - if (!my_charset_same(cs, system_charset_info)) - { - size_t res_length; - name.str= sql_strmake_with_convert(thd, str, length, cs, - MAX_ALIAS_NAME, system_charset_info, - &res_length); - name.length= res_length; - } - else - name.str= thd->strmake(str, (name.length= MY_MIN(length,MAX_ALIAS_NAME))); + name= make_name(thd, str, length, cs, MAX_ALIAS_NAME - 1); } void Item::set_name_no_truncate(THD *thd, const char *str, uint length, CHARSET_INFO *cs) { - if (!my_charset_same(cs, system_charset_info)) - { - size_t res_length; - name.str= sql_strmake_with_convert(thd, str, length, cs, - UINT_MAX, system_charset_info, - &res_length); - name.length= res_length; - } - else - name.str= thd->strmake(str, (name.length= length)); + name= make_name(thd, str, length, cs, UINT_MAX - 1); } |