diff options
author | Alexander Barkov <bar@mariadb.com> | 2022-12-14 18:46:27 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2023-03-21 10:07:57 +0400 |
commit | 8d51c6d234b1730d4ff3b2c1fe7828eeca81998b (patch) | |
tree | 4a0d7ff0038e218b3f9de741c18fa7c8409fdf3c /sql/sql_prepare.cc | |
parent | ceb0e7f944b5c252d999ac06012ac0e05925c0b2 (diff) | |
download | mariadb-git-bb-10.11-bar-collations.tar.gz |
MDEV-30164 System variable for default collationsbb-10.11-bar-collations
This patch adds a way to override default collations
(or "character set collations") for desired character sets.
The SQL standard says:
> Each collation known in an SQL-environment is applicable to one
> or more character sets, and for each character set, one or more
> collations are applicable to it, one of which is associated with
> it as its character set collation.
In MariaDB, character set collations has been hard-coded so far,
e.g. utf8mb4_general_ci has been a hard-coded character set collation
for utf8mb4.
This patch allows to override (globally per server, or per session)
character set collations, so for example, uca1400_ai_ci can be set as a
character set collation for Unicode character sets
(instead of compiled xxx_general_ci).
The array of overridden character set collations is stored in a new
(session and global) system variable @@character_set_collations and
can be set as a comma separated list of charset=collation pairs, e.g.:
SET @@character_set_collations='utf8mb3=uca1400_ai_ci,utf8mb4=uca1400_ai_ci';
The variable is empty by default, which mean use the hard-coded
character set collations (e.g. utf8mb4_general_ci for utf8mb4).
The variable can also be set globally by passing to the server startup command
line, and/or in my.cnf.
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r-- | sql/sql_prepare.cc | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1e84471eef2..7c1930dcbe9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -209,6 +209,7 @@ public: inline bool is_sql_prepare() const { return flags & (uint) IS_SQL_PREPARE; } void set_sql_prepare() { flags|= (uint) IS_SQL_PREPARE; } bool prepare(const char *packet, uint packet_length); + bool reprepare(); bool execute_loop(String *expanded_query, bool open_cursor, uchar *packet_arg, uchar *packet_end_arg); @@ -221,6 +222,10 @@ public: /* Destroy this statement */ void deallocate(); bool execute_immediate(const char *query, uint query_length); + uint prepare_time_charset_collation_map_version() const + { + return m_prepare_time_charset_collation_map_version; + } private: /** The memory root to allocate parsed tree elements (instances of Item, @@ -228,13 +233,14 @@ private: */ MEM_ROOT main_mem_root; sql_mode_t m_sql_mode; + THD::used_t m_prepare_time_thd_used_flags; + uint m_prepare_time_charset_collation_map_version; private: bool set_db(const LEX_CSTRING *db); bool set_parameters(String *expanded_query, uchar *packet, uchar *packet_end); bool execute(String *expanded_query, bool open_cursor); void deallocate_immediate(); - bool reprepare(); bool validate_metadata(Prepared_statement *copy); void swap_prepared_statement(Prepared_statement *copy); }; @@ -3538,6 +3544,13 @@ static void mysql_stmt_execute_common(THD *thd, DBUG_VOID_RETURN; } + if (stmt->prepare_time_charset_collation_map_version() != + thd->variables.character_set_collations.version()) + { + if (stmt->reprepare()) + DBUG_VOID_RETURN; + } + /* In case of direct execution application decides how many parameters to send. @@ -3628,6 +3641,13 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_VOID_RETURN; } + if (stmt->prepare_time_charset_collation_map_version() != + thd->variables.character_set_collations.version()) + { + if (stmt->reprepare()) + DBUG_VOID_RETURN; + } + if (stmt->param_count != lex->prepared_stmt.param_count()) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); @@ -4125,7 +4145,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg) iterations(0), start_param(0), read_types(0), - m_sql_mode(thd->variables.sql_mode) + m_sql_mode(thd->variables.sql_mode), + m_prepare_time_thd_used_flags(0), + m_prepare_time_charset_collation_map_version(0) { init_sql_alloc(key_memory_prepared_statement_main_mem_root, &main_mem_root, thd_arg->variables.query_alloc_block_size, @@ -4505,6 +4527,9 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) } // The same format as for triggers to compare hr_prepare_time= my_hrtime(); + m_prepare_time_thd_used_flags= thd->used; + m_prepare_time_charset_collation_map_version= + thd->variables.character_set_collations.version(); DBUG_RETURN(error); } @@ -5060,6 +5085,13 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy) /* Ditto */ swap_variables(LEX_CSTRING, db, copy->db); + swap_variables(uint, + m_prepare_time_charset_collation_map_version, + copy->m_prepare_time_charset_collation_map_version); + swap_variables(THD::used_t, + m_prepare_time_thd_used_flags, + copy->m_prepare_time_thd_used_flags); + DBUG_ASSERT(param_count == copy->param_count); DBUG_ASSERT(thd == copy->thd); last_error[0]= '\0'; @@ -5220,6 +5252,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) MYSQL_QUERY_EXEC_START(thd->query(), thd->thread_id, thd->get_db(), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 1); + /* + If PREPARE used @@character_set_collations, + then we need to make sure binary log writes + the map in the event header. + */ + thd->used|= m_prepare_time_thd_used_flags & + THD::CHARACTER_SET_COLLATIONS_USED; error= mysql_execute_command(thd, true); MYSQL_QUERY_EXEC_DONE(error); thd->update_server_status(); |