/* Copyright (c) 2023, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" #include "my_sys.h" #include "lex_charset.h" #include "mysqld_error.h" #include "charset_collations.h" #include "simple_tokenizer.h" bool Charset_collation_map_st::insert_or_replace( const Lex_exact_charset &charset, const Lex_extended_collation &collation, bool error_on_conflicting_duplicate) { Lex_exact_charset_opt_extended_collate res(charset); Sql_used used; if (res.merge_collation_override(&used, *this, collation)) return true; if (error_on_conflicting_duplicate) { const Elem_st *dup; if ((dup= find_elem_by_charset_id(charset.charset_info()->number)) && dup->to() != res.collation().charset_info()) { my_error(ER_CONFLICTING_DECLARATIONS, MYF(0), "", dup->to()->coll_name.str, "", res.collation().charset_info()->coll_name.str); return true; } } return insert_or_replace(Elem(charset.charset_info(), res.collation().charset_info())); } bool Charset_collation_map_st::insert_or_replace( const LEX_CSTRING &cs_name, const LEX_CSTRING &cl_name, bool error_on_conflicting_duplicate, myf utf8_flag) { char charset_name_c[MY_CS_CHARACTER_SET_NAME_SIZE + 1/*for '\0'*/]; strmake(charset_name_c, cs_name.str, cs_name.length); CHARSET_INFO *cs= get_charset_by_csname(charset_name_c, MY_CS_PRIMARY, utf8_flag); if (!cs) { my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), charset_name_c); return true; } char collation_name_c[MY_CS_COLLATION_NAME_SIZE + 1/*for '\0'*/]; strmake(collation_name_c, cl_name.str, cl_name.length); Lex_exact_collation tmpec(&my_charset_bin); Lex_extended_collation tmp(tmpec); if (tmp.set_by_name(collation_name_c, utf8_flag)) return true; return insert_or_replace(Lex_exact_charset(cs), tmp, error_on_conflicting_duplicate); } bool Charset_collation_map_st::from_text(const LEX_CSTRING &str, myf utf8_flag) { init(); Simple_tokenizer stream(str.str, str.length); /* Allow relaxed comma parsing: SET @@character_set_collations= ',,,utf8mb3 = utf8mb3_bin,,latin1 = latin1_bin,,,'; It makes it easier for the user to edit the value using SQL functions CONCAT or REGEXP_REPLACE. */ for ( ; ; ) { LEX_CSTRING charset_name= stream.get_ident(); if (charset_name.length) { if (stream.get_char('=')) return true; LEX_CSTRING collation_name= stream.get_ident(); if (!collation_name.length) return true; /* Don't allow duplicate conflicting declarations within the same string: SET @@var='utf8mb3=utf8mb3_general_ci,utf8mb3=utf8mb3_bin'; */ if (insert_or_replace(charset_name, collation_name, true/*err on dup*/, utf8_flag)) return true; } if (!stream.get_char(',')) continue; if (stream.eof()) return false; return true; } return false; }