MDEV-34288 SET NAMES DEFAULT crashes mariadbd --collation-server=utf8mb4_unicode_ci

The @@global.character_set_client variable could erroneously be set
to a non-default collation of its character set, which further made
the `SET NAMES DEFAULT` statement crash the server.

Fixing the code to make sure that the global value these variables:
  @@character_set_client
  @@character_set_connection
  @@character_set_server
  @@character_set_database
  @@character_set_connection
point to the default compiled collations of the character set.
This commit is contained in:
Alexander Barkov 2024-06-04 12:00:20 +04:00
parent d61947550a
commit 76e0dc18b6
9 changed files with 156 additions and 16 deletions

View file

@ -9,3 +9,48 @@ DROP TABLE t1;
#
# End of 10.3 tests
#
#
# Start of 10.11 tests
#
#
# MDEV-34288 SET NAMES DEFAULT crashes `mariadbd --collation-server=utf8mb4_unicode_ci`
#
SET NAMES DEFAULT COLLATE latin1_bin;
ERROR 42000: COLLATION 'latin1_bin' is not valid for CHARACTER SET 'utf8mb4'
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
latin1 latin1_swedish_ci latin1
SET NAMES DEFAULT COLLATE utf8mb4_bin;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb4 utf8mb4_bin utf8mb4
SET NAMES DEFAULT COLLATE uca1400_ai_ci;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb4 utf8mb4_uca1400_ai_ci utf8mb4
SET @@global.character_set_client=latin1;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
latin1 latin1_swedish_ci latin1
SET @@global.character_set_client=utf8mb3;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb3 utf8mb3_general_ci utf8mb3
SET @@global.character_set_client=DEFAULT;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb4 utf8mb4_general_ci utf8mb4
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb4 utf8mb4_general_ci utf8mb4
SET NAMES DEFAULT COLLATE DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
@@character_set_connection @@collation_connection @@character_set_results
utf8mb4 utf8mb4_general_ci utf8mb4
#
# End of 10.11 tests
#

View file

@ -13,3 +13,45 @@ DROP TABLE t1;
--echo #
--echo # End of 10.3 tests
--echo #
--echo #
--echo # Start of 10.11 tests
--echo #
--echo #
--echo # MDEV-34288 SET NAMES DEFAULT crashes `mariadbd --collation-server=utf8mb4_unicode_ci`
--echo #
--error ER_COLLATION_CHARSET_MISMATCH
SET NAMES DEFAULT COLLATE latin1_bin;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET NAMES DEFAULT COLLATE utf8mb4_bin;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET NAMES DEFAULT COLLATE uca1400_ai_ci;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET @@global.character_set_client=latin1;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET @@global.character_set_client=utf8mb3;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET @@global.character_set_client=DEFAULT;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET NAMES DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
SET NAMES DEFAULT COLLATE DEFAULT;
SELECT @@character_set_connection, @@collation_connection, @@character_set_results;
--echo #
--echo # End of 10.11 tests
--echo #

View file

@ -288,6 +288,12 @@ public:
DBUG_ASSERT(0);
return m_ci->coll_name;
}
static Lex_extended_collation_st collate_default()
{
Lex_extended_collation_st res;
res.set_collate_default();
return res;
}
void set_collate_default()
{
m_ci= &my_collation_contextually_typed_default;

View file

@ -4329,8 +4329,10 @@ static int init_common_variables()
if (is_supported_parser_charset(default_charset_info))
{
global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
global_system_variables.character_set_results=
global_system_variables.character_set_client=
Lex_exact_charset_opt_extended_collate(default_charset_info, true).
find_default_collation();
}
else
{

View file

@ -12131,10 +12131,31 @@ bool LEX::sp_create_set_password_instr(THD *thd,
}
/*
Handle the SET NAMES statement variants, e.g.:
SET NAMES DEFAULT;
SET NAMES DEFAULT COLLATE DEFAULT;
SET NAMES DEFAULT COLLATE latin1_bin;
SET NAMES latin1;
SET NAMES latin1 COLLATE DEFAULT;
SET NAMES latin1 COLLATE latin1_bin;
SET NAMES utf8mb4 COLLATE uca1400_ai_ci;
@param pos - The position of the keyword `NAMES` inside the query
@param cs - The character set part, or nullptr if DEFAULT
@param cl - The collation (explicit or contextually typed)
@param no_lookahead - The tokinizer lookahead state
*/
bool LEX::set_names(const char *pos,
const Lex_exact_charset_opt_extended_collate &cscl,
CHARSET_INFO *cs,
const Lex_extended_collation_st &cl,
bool no_lookahead)
{
CHARSET_INFO *def= global_system_variables.character_set_client;
Lex_exact_charset_opt_extended_collate cscl(cs ? cs : def, true);
if (cscl.merge_collation_override(cl))
return true;
if (sp_create_assignment_lex(thd, pos))
return true;
CHARSET_INFO *ci= cscl.collation().charset_info();

View file

@ -3873,7 +3873,8 @@ public:
int case_stmt_action_then();
bool setup_select_in_parentheses();
bool set_names(const char *pos,
const Lex_exact_charset_opt_extended_collate &cs,
CHARSET_INFO *cs,
const Lex_extended_collation_st &coll,
bool no_lookahead);
bool set_trigger_new_row(const LEX_CSTRING *name, Item *val);
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,

View file

@ -16671,18 +16671,15 @@ option_value_no_option_type:
}
| NAMES_SYM charset_name_or_default
{
CHARSET_INFO *def= global_system_variables.character_set_client;
Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
if (Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
if (Lex->set_names($1.pos(), $2,
Lex_extended_collation_st::collate_default(),
yychar == YYEMPTY))
MYSQL_YYABORT;
}
| NAMES_SYM charset_name_or_default
COLLATE_SYM collation_name_or_default
{
CHARSET_INFO *def= global_system_variables.character_set_client;
Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
if (tmp.merge_collation($4) ||
Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
if (Lex->set_names($1.pos(), $2, $4, yychar == YYEMPTY))
MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role

View file

@ -824,7 +824,7 @@ static Sys_var_struct Sys_character_set_system(
READ_ONLY GLOBAL_VAR(system_charset_info), NO_CMD_LINE,
offsetof(CHARSET_INFO, cs_name.str), DEFAULT(0));
static Sys_var_struct Sys_character_set_server(
static Sys_var_charset Sys_character_set_server(
"character_set_server", "The default character set",
SESSION_VAR(collation_server), NO_CMD_LINE,
offsetof(CHARSET_INFO, cs_name.str), DEFAULT(&default_charset_info),
@ -838,7 +838,7 @@ static bool check_charset_db(sys_var *self, THD *thd, set_var *var)
var->save_result.ptr= thd->db_charset;
return false;
}
static Sys_var_struct Sys_character_set_database(
static Sys_var_charset Sys_character_set_database(
"character_set_database",
"The character set used by the default database",
SESSION_VAR(collation_database), NO_CMD_LINE,
@ -862,7 +862,8 @@ static bool fix_thd_charset(sys_var *self, THD *thd, enum_var_type type)
thd->update_charset();
return false;
}
static Sys_var_struct Sys_character_set_client(
static Sys_var_charset Sys_character_set_client(
"character_set_client", "The character set for statements "
"that arrive from the client",
NO_SET_STMT SESSION_VAR(character_set_client), NO_CMD_LINE,
@ -872,7 +873,7 @@ static Sys_var_struct Sys_character_set_client(
// for check changing
export sys_var *Sys_character_set_client_ptr= &Sys_character_set_client;
static Sys_var_struct Sys_character_set_connection(
static Sys_var_charset Sys_character_set_connection(
"character_set_connection", "The character set used for "
"literals that do not have a character set introducer and for "
"number-to-string conversion",
@ -883,7 +884,7 @@ static Sys_var_struct Sys_character_set_connection(
// for check changing
export sys_var *Sys_character_set_connection_ptr= &Sys_character_set_connection;
static Sys_var_struct Sys_character_set_results(
static Sys_var_charset Sys_character_set_results(
"character_set_results", "The character set used for returning "
"query results to the client",
SESSION_VAR(character_set_results), NO_CMD_LINE,

View file

@ -2166,6 +2166,31 @@ public:
{ return valptr(thd, *(uchar**)option.def_value); }
};
/**
The class to store character sets.
*/
class Sys_var_charset: public Sys_var_struct
{
public:
using Sys_var_struct::Sys_var_struct;
void global_save_default(THD *thd, set_var *var)
{
/*
The default value can point to an arbitrary collation,
e.g. default_charset_info.
Let's convert it to the compiled default collation.
This makes the code easier in various places such as SET NAMES.
*/
void **default_value= reinterpret_cast<void**>(option.def_value);
var->save_result.ptr=
Lex_exact_charset_opt_extended_collate((CHARSET_INFO *) *default_value,
true).
find_default_collation();
}
};
/**
The class for variables that store time zones