1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-31340 Remove MY_COLLATION_HANDLER::strcasecmp()

This patch also fixes:
  MDEV-33050 Build-in schemas like oracle_schema are accent insensitive
  MDEV-33084 LASTVAL(t1) and LASTVAL(T1) do not work well with lower-case-table-names=0
  MDEV-33085 Tables T1 and t1 do not work well with ENGINE=CSV and lower-case-table-names=0
  MDEV-33086 SHOW OPEN TABLES IN DB1 -- is case insensitive with lower-case-table-names=0
  MDEV-33088 Cannot create triggers in the database `MYSQL`
  MDEV-33103 LOCK TABLE t1 AS t2 -- alias is not case sensitive with lower-case-table-names=0
  MDEV-33109 DROP DATABASE MYSQL -- does not drop SP with lower-case-table-names=0
  MDEV-33110 HANDLER commands are case insensitive with lower-case-table-names=0
  MDEV-33119 User is case insensitive in INFORMATION_SCHEMA.VIEWS
  MDEV-33120 System log table names are case insensitive with lower-cast-table-names=0

- Removing the virtual function strnncoll() from MY_COLLATION_HANDLER

- Adding a wrapper function CHARSET_INFO::streq(), to compare
  two strings for equality. For now it calls strnncoll() internally.
  In the future it will turn into a virtual function.

- Adding new accent sensitive case insensitive collations:
    - utf8mb4_general1400_as_ci
    - utf8mb3_general1400_as_ci
  They implement accent sensitive case insensitive comparison.
  The weight of a character is equal to the code point of its
  upper case variant. These collations use Unicode-14.0.0 casefolding data.

  The result of
     my_charset_utf8mb3_general1400_as_ci.strcoll()
  is very close to the former
     my_charset_utf8mb3_general_ci.strcasecmp()

  There is only a difference in a couple dozen rare characters, because:
    - the switch from "tolower" to "toupper" comparison, to make
      utf8mb3_general1400_as_ci closer to utf8mb3_general_ci
    - the switch from Unicode-3.0.0 to Unicode-14.0.0
  This difference should be tolarable. See the list of affected
  characters in the MDEV description.

  Note, utf8mb4_general1400_as_ci correctly handles non-BMP characters!
  Unlike utf8mb4_general_ci, it does not treat all BMP characters
  as equal.

- Adding classes representing names of the file based database objects:

    Lex_ident_db
    Lex_ident_table
    Lex_ident_trigger

  Their comparison collation depends on the underlying
  file system case sensitivity and on --lower-case-table-names
  and can be either my_charset_bin or my_charset_utf8mb3_general1400_as_ci.

- Adding classes representing names of other database objects,
  whose names have case insensitive comparison style,
  using my_charset_utf8mb3_general1400_as_ci:

  Lex_ident_column
  Lex_ident_sys_var
  Lex_ident_user_var
  Lex_ident_sp_var
  Lex_ident_ps
  Lex_ident_i_s_table
  Lex_ident_window
  Lex_ident_func
  Lex_ident_partition
  Lex_ident_with_element
  Lex_ident_rpl_filter
  Lex_ident_master_info
  Lex_ident_host
  Lex_ident_locale
  Lex_ident_plugin
  Lex_ident_engine
  Lex_ident_server
  Lex_ident_savepoint
  Lex_ident_charset
  engine_option_value::Name

- All the mentioned Lex_ident_xxx classes implement a method streq():

  if (ident1.streq(ident2))
     do_equal();

  This method works as a wrapper for CHARSET_INFO::streq().

- Changing a lot of "LEX_CSTRING name" to "Lex_ident_xxx name"
  in class members and in function/method parameters.

- Replacing all calls like
    system_charset_info->coll->strcasecmp(ident1, ident2)
  to
    ident1.streq(ident2)

- Taking advantage of the c++11 user defined literal operator
  for LEX_CSTRING (see m_strings.h) and Lex_ident_xxx (see lex_ident.h)
  data types. Use example:

  const Lex_ident_column primary_key_name= "PRIMARY"_Lex_ident_column;

  is now a shorter version of:

  const Lex_ident_column primary_key_name=
    Lex_ident_column({STRING_WITH_LEN("PRIMARY")});
This commit is contained in:
Alexander Barkov
2023-04-26 15:27:01 +04:00
parent 159b7ca3f2
commit fd247cc21f
204 changed files with 8971 additions and 3202 deletions

View File

@ -1129,10 +1129,9 @@ void cleanup_items(Item *item)
#ifdef WITH_WSREP
static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables)
{
for (const TABLE_LIST *table= tables; table; table= table->next_global)
for (const TABLE_LIST *t= tables; t; t= t->next_global)
{
LEX_CSTRING db= table->db, tn= table->table_name;
if (get_table_category(&db, &tn) < TABLE_CATEGORY_INFORMATION)
if (get_table_category(t->db, t->table_name) < TABLE_CATEGORY_INFORMATION)
return false;
}
return tables != NULL;
@ -2033,7 +2032,7 @@ dispatch_command_return dispatch_command(enum enum_server_command command, THD *
}
thd->convert_string(&table_name, system_charset_info,
packet, arg_length, thd->charset());
if (check_table_name(table_name.str, table_name.length, FALSE))
if (Lex_ident_table::check_name(table_name, false))
{
/* this is OK due to convert_string() null-terminating the string */
my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
@ -2648,7 +2647,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
lex->first_select_lex()->db=
thd->make_ident_casedn(lex->first_select_lex()->db);
schema_select_lex->db= lex->first_select_lex()->db;
if (Lex_ident_fs(lex->first_select_lex()->db).check_db_name_with_error())
if (Lex_ident_db::check_name_with_error(lex->first_select_lex()->db))
DBUG_RETURN(1);
break;
}
@ -2831,8 +2830,8 @@ bool sp_process_definer(THD *thd)
bool curuser= !strcmp(d->user.str, thd->security_ctx->priv_user);
bool currole= !curuser && !strcmp(d->user.str, thd->security_ctx->priv_role);
bool curuserhost= curuser && d->host.str &&
!my_strcasecmp(system_charset_info, d->host.str,
thd->security_ctx->priv_host);
Lex_ident_host(d->host).
streq(Lex_cstring_strlen(thd->security_ctx->priv_host));
if (!curuserhost && !currole &&
check_global_access(thd, PRIV_DEFINER_CLAUSE, false))
DBUG_RETURN(TRUE);
@ -2841,7 +2840,7 @@ bool sp_process_definer(THD *thd)
/* Check that the specified definer exists. Emit a warning if not. */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
if (!is_acl_user(lex->definer->host, lex->definer->user))
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER, ER_THD(thd, ER_NO_SUCH_USER),
@ -3073,7 +3072,7 @@ mysql_create_routine(THD *thd, LEX *lex)
DBUG_ASSERT(lower_case_table_names != 1 ||
Lex_ident_fs(lex->sphead->m_db).is_in_lower_case());
if (Lex_ident_fs(lex->sphead->m_db).check_db_name_with_error())
if (Lex_ident_db::check_name_with_error(lex->sphead->m_db))
return true;
if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str,
@ -3089,15 +3088,15 @@ mysql_create_routine(THD *thd, LEX *lex)
return true;
}
const LEX_CSTRING *name= lex->sphead->name();
const Lex_ident_routine name= Lex_ident_routine(*lex->sphead->name());
#ifdef HAVE_DLOPEN
if (lex->sphead->m_handler->type() == SP_TYPE_FUNCTION)
{
udf_func *udf = find_udf(name->str, name->length);
udf_func *udf= find_udf(name.str, name.length);
if (udf)
{
my_error(ER_UDF_EXISTS, MYF(0), name->str);
my_error(ER_UDF_EXISTS, MYF(0), name.str);
return true;
}
}
@ -3141,7 +3140,7 @@ mysql_create_routine(THD *thd, LEX *lex)
which doesn't any check routine privileges,
so no routine privilege record will insert into mysql.procs_priv.
*/
if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str))
if (thd->slave_thread && is_acl_user(definer->host, definer->user))
{
security_context.change_security_context(thd, &thd->lex->definer->user,
&thd->lex->definer->host,
@ -3152,10 +3151,10 @@ mysql_create_routine(THD *thd, LEX *lex)
if (sp_automatic_privileges && !opt_noacl &&
check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
&lex->sphead->m_db, name,
&lex->sphead->m_db, &name,
Sp_handler::handler(lex->sql_command), 1))
{
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str,
if (sp_grant_privileges(thd, lex->sphead->m_db, name,
Sp_handler::handler(lex->sql_command)))
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
@ -5568,7 +5567,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
case SQLCOM_SHOW_PACKAGE_BODY_CODE:
{
#ifndef DBUG_OFF
Database_qualified_name pkgname(&null_clex_str, &null_clex_str);
Database_qualified_name pkgname;
sp_head *sp;
const Sp_handler *sph= Sp_handler::handler(lex->sql_command);
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
@ -6192,15 +6191,15 @@ static TABLE *find_temporary_table_for_rename(THD *thd,
{
TABLE_LIST *next= table->next_local;
if (!strcmp(table->get_db_name(), cur_table->get_db_name()) &&
!strcmp(table->get_table_name(), cur_table->get_table_name()))
if (!strcmp(table->get_db_name().str, cur_table->get_db_name().str) &&
!strcmp(table->get_table_name().str, cur_table->get_table_name().str))
{
/* Table was moved away, can't be same as 'table' */
found= 1;
res= 0; // Table can't be a temporary table
}
if (!strcmp(next->get_db_name(), cur_table->get_db_name()) &&
!strcmp(next->get_table_name(), cur_table->get_table_name()))
if (!strcmp(next->get_db_name().str, cur_table->get_db_name().str) &&
!strcmp(next->get_table_name().str, cur_table->get_table_name().str))
{
/*
Table has matching name with new name of this table. cur_table should
@ -6305,7 +6304,7 @@ show_create_db(THD *thd, LEX *lex)
my_error(ER_UNKNOWN_ERROR, MYF(0)); return 1;);
const DBNameBuffer dbbuf(lex->name, lower_case_table_names == 1);
if (Lex_ident_fs(dbbuf.to_lex_cstring()).check_db_name_with_error())
if (Lex_ident_db::check_name_with_error(dbbuf.to_lex_cstring()))
return 1;
LEX_CSTRING db= dbbuf.to_lex_cstring();
return mysqld_show_create_db(thd, &db, &lex->name, lex->create_info);
@ -6423,7 +6422,8 @@ absent:
if (sp_result != SP_KEY_NOT_FOUND &&
sp_automatic_privileges && !opt_noacl &&
sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str,
sp_revoke_privileges(thd, lex->spname->m_db,
Lex_ident_routine(lex->spname->m_name),
Sp_handler::handler(lex->sql_command)))
{
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
@ -6953,7 +6953,7 @@ check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables,
}
if (check_access(thd, want_access,
table_ref->get_db_name(),
table_ref->get_db_name().str,
&table_ref->grant.privilege,
&table_ref->grant.m_internal,
0, no_errors))
@ -6973,8 +6973,8 @@ check_routine_access(THD *thd, privilege_t want_access, const LEX_CSTRING *db,
TABLE_LIST tables[1];
bzero((char *)tables, sizeof(TABLE_LIST));
tables->db= *db;
tables->table_name= tables->alias= *name;
tables->db= Lex_ident_db(*db);
tables->table_name= tables->alias= Lex_ident_table(*name);
/*
The following test is just a shortcut for check_access() (to avoid
@ -7145,7 +7145,7 @@ bool check_fk_parent_table_access(THD *thd,
// Check if tablename is valid or not.
DBUG_ASSERT(table_name.str != NULL);
if (check_table_name(table_name.str, table_name.length, false))
if (Lex_ident_table::check_name(table_name, false))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
return true;
@ -7157,7 +7157,7 @@ bool check_fk_parent_table_access(THD *thd,
if (fk_key->ref_db.str)
{
if (Lex_ident_fs(fk_key->ref_db).check_db_name_with_error() ||
if (Lex_ident_db::check_name_with_error(fk_key->ref_db) ||
!(db_name= thd->make_ident_opt_casedn(fk_key->ref_db,
lower_case_table_names)).str)
return true;
@ -7167,7 +7167,7 @@ bool check_fk_parent_table_access(THD *thd,
if (!thd->db.str)
{
DBUG_ASSERT(create_db.str);
if (Lex_ident_fs(create_db).check_db_name_with_error() ||
if (Lex_ident_db::check_name_with_error(create_db) ||
!(db_name= thd->make_ident_opt_casedn(create_db,
lower_case_table_names)).str)
return true;
@ -7980,7 +7980,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
TABLE_LIST *ptr;
TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */
LEX_CSTRING alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
DBUG_PRINT("enter", ("Table '%s' (%p) Select %p (%u)",
@ -7991,10 +7990,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (unlikely(!table))
DBUG_RETURN(0); // End of memory
alias_str= alias ? *alias : table->table;
Lex_ident_table alias_str= alias ? Lex_ident_table(*alias) :
Lex_ident_table(table->table);
DBUG_ASSERT(alias_str.str);
if (!MY_TEST(table_options & TL_OPTION_ALIAS) &&
unlikely(check_table_name(table->table.str, table->table.length, FALSE)))
unlikely(Lex_ident_table::check_name(table->table, false)))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
DBUG_RETURN(0);
@ -8002,7 +8002,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (unlikely(table->is_derived_table() == FALSE && table->db.str &&
!(table_options & TL_OPTION_TABLE_FUNCTION) &&
Lex_ident_fs(table->db).check_db_name_with_error()))
Lex_ident_db::check_name_with_error(table->db)))
DBUG_RETURN(0);
if (!alias) /* Alias is case sensitive */
@ -8022,7 +8022,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (table->db.str)
{
ptr->is_fqtn= TRUE;
ptr->db= table->db;
ptr->db= Lex_ident_db(table->db);
}
else if (!lex->with_cte_resolution && lex->copy_db_to(&ptr->db))
DBUG_RETURN(0);
@ -8031,14 +8031,14 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->alias= alias_str;
ptr->is_alias= alias ? TRUE : FALSE;
ptr->table_name= table->table;
ptr->table_name= Lex_ident_table(table->table);
if (lower_case_table_names)
{
if (!(ptr->table_name= thd->make_ident_casedn(ptr->table_name)).str)
if (!(ptr->table_name= thd->lex_ident_casedn(ptr->table_name)).str)
DBUG_RETURN(0);
if (ptr->db.length && ptr->db.str != any_db.str &&
!(ptr->db= thd->make_ident_casedn(ptr->db)).str)
!(ptr->db= thd->lex_ident_casedn(ptr->db)).str)
DBUG_RETURN(0);
}
@ -8064,7 +8064,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
ST_SCHEMA_TABLE *schema_table;
schema_table= find_schema_table(thd, &ptr->table_name);
ptr->schema_table_name= ptr->table_name;
ptr->schema_table_name= Lex_ident_i_s_table(ptr->table_name);
ptr->schema_table= schema_table;
}
ptr->select_lex= this;
@ -8085,8 +8085,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
tables ;
tables=tables->next_local)
{
if (unlikely(!my_strcasecmp(table_alias_charset, alias_str.str,
tables->alias.str) &&
if (unlikely(alias_str.streq(tables->alias) &&
(tables->db.str == any_db.str || ptr->db.str == any_db.str ||
!cmp(&ptr->db, &tables->db)) &&
!tables->sequence))
@ -9451,12 +9450,12 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl,
if (tbl->is_fqtn && elem->is_alias)
continue; /* no match */
if (tbl->is_fqtn && elem->is_fqtn)
res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) ||
res= (!tbl->table_name.streq(elem->table_name) ||
cmp(&tbl->db, &elem->db));
else if (elem->is_alias)
res= my_strcasecmp(table_alias_charset, tbl->alias.str, elem->alias.str);
res= !tbl->alias.streq(elem->alias);
else
res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) ||
res= (!tbl->table_name.streq(elem->table_name) ||
cmp(&tbl->db, &elem->db));
if (res)
@ -9974,7 +9973,8 @@ bool check_string_char_length(const LEX_CSTRING *str, uint err_msg,
bool check_ident_length(const LEX_CSTRING *ident)
{
if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1))
if (check_string_char_length(ident, 0, NAME_CHAR_LEN,
Lex_ident_ci::charset_info(), 1))
{
my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str);
return 1;