From a2a2e32c02643a0cec111511220227703fda1cd5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 1 Jul 2024 20:15:00 +0200 Subject: Merging upstream version 1:11.4.2. Signed-off-by: Daniel Baumann --- sql/sql_db.cc | 185 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 82 insertions(+), 103 deletions(-) (limited to 'sql/sql_db.cc') diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 2d582eb8..08441d9f 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -55,7 +55,8 @@ const char *del_exts[]= {".BAK", ".opt", NullS}; static TYPELIB deletable_extensions= {array_elements(del_exts)-1,"del_exts", del_exts, NULL}; -static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, const char *, +static bool find_db_tables_and_rm_known_files(THD *, MY_DIR *, + const Lex_ident_db_normalized &db, const char *, TABLE_LIST **); long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); @@ -64,7 +65,7 @@ static void mysql_change_db_impl(THD *thd, LEX_CSTRING *new_db_name, privilege_t new_db_access, CHARSET_INFO *new_db_charset); -static bool mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, +static bool mysql_rm_db_internal(THD *thd, const Lex_ident_db &db, bool if_exists, bool silent); @@ -727,7 +728,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name) */ static int -mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, +mysql_create_db_internal(THD *thd, const Lex_ident_db &db, const DDL_options_st &options, Schema_specification_st *create_info, bool silent) @@ -738,20 +739,20 @@ mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, DBUG_ENTER("mysql_create_db"); /* do not create 'information_schema' db */ - if (is_infoschema_db(db)) + if (is_infoschema_db(&db)) { - my_error(ER_DB_CREATE_EXISTS, MYF(0), db->str); + my_error(ER_DB_CREATE_EXISTS, MYF(0), db.str); DBUG_RETURN(-1); } - char db_tmp[SAFE_NAME_LEN+1]; - const char *dbnorm= normalize_db_name(db->str, db_tmp, sizeof(db_tmp)); + const DBNameBuffer dbnorm_buffer(db, lower_case_table_names); + Lex_ident_db_normalized dbnorm(dbnorm_buffer.to_lex_cstring()); if (lock_schema_name(thd, dbnorm)) DBUG_RETURN(-1); /* Check directory */ - path_len= build_table_filename(path, sizeof(path) - 1, db->str, "", "", 0); + path_len= build_table_filename(path, sizeof(path) - 1, db.str, "", "", 0); path[path_len-1]= 0; // Remove last '/' from path long affected_rows= 1; @@ -779,19 +780,19 @@ mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DB_CREATE_EXISTS, ER_THD(thd, ER_DB_CREATE_EXISTS), - db->str); + db.str); affected_rows= 0; goto not_silent; } else { - my_error(ER_DB_CREATE_EXISTS, MYF(0), db->str); + my_error(ER_DB_CREATE_EXISTS, MYF(0), db.str); DBUG_RETURN(-1); } if (my_mkdir(path, 0777, MYF(0)) < 0) { - my_error(ER_CANT_CREATE_DB, MYF(0), db->str, my_errno); + my_error(ER_CANT_CREATE_DB, MYF(0), db.str, my_errno); DBUG_RETURN(-1); } @@ -819,7 +820,7 @@ mysql_create_db_internal(THD *thd, const LEX_CSTRING *db, bzero(&ddl_log, sizeof(ddl_log)); ddl_log.query= { C_STRING_WITH_LEN("CREATE") }; ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; - ddl_log.org_database= *db; + ddl_log.org_database= db; backup_log_ddl(&ddl_log); not_silent: @@ -855,8 +856,8 @@ not_silent: USE sisyfos; # Will give error on slave since # database does not exist. */ - qinfo.db = db->str; - qinfo.db_len = (uint32)db->length; + qinfo.db = db.str; + qinfo.db_len = (uint32)db.length; /* These DDL methods and logging are protected with the exclusive @@ -875,7 +876,7 @@ not_silent: /* db-name is already validated when we come here */ static bool -mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, +mysql_alter_db_internal(THD *thd, const Lex_ident_db &db, Schema_specification_st *create_info) { char path[FN_REFLEN+16]; @@ -883,9 +884,9 @@ mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, int error= 0; DBUG_ENTER("mysql_alter_db"); - char dbnorm_buffer[SAFE_NAME_LEN + 1]; - const char *dbnorm= normalize_db_name(db->str, dbnorm_buffer, - sizeof(dbnorm_buffer)); + const DBNameBuffer dbnorm_buffer(db, lower_case_table_names); + Lex_ident_db_normalized dbnorm(dbnorm_buffer.to_lex_cstring()); + if (lock_schema_name(thd, dbnorm)) DBUG_RETURN(TRUE); @@ -894,13 +895,13 @@ mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, We pass MY_DB_OPT_FILE as "extension" to avoid "table name to file name" encoding. */ - build_table_filename(path, sizeof(path) - 1, db->str, "", MY_DB_OPT_FILE, 0); + build_table_filename(path, sizeof(path) - 1, db.str, "", MY_DB_OPT_FILE, 0); if (unlikely((error=write_db_opt(thd, path, create_info)))) goto exit; /* Change options if current database is being altered. */ - if (thd->db.str && !cmp(&thd->db, db)) + if (thd->db.str && !cmp(&thd->db, &db)) { thd->db_charset= create_info->default_table_charset ? create_info->default_table_charset : @@ -913,7 +914,7 @@ mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, bzero(&ddl_log, sizeof(ddl_log)); ddl_log.query= { C_STRING_WITH_LEN("ALTER") }; ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; - ddl_log.org_database= *db; + ddl_log.org_database= db; backup_log_ddl(&ddl_log); if (mysql_bin_log.is_open()) @@ -926,8 +927,8 @@ mysql_alter_db_internal(THD *thd, const LEX_CSTRING *db, database" and not the threads current database, which is the default. */ - qinfo.db= db->str; - qinfo.db_len= (uint)db->length; + qinfo.db= db.str; + qinfo.db_len= (uint) db.length; /* These DDL methods and logging are protected with the exclusive @@ -943,7 +944,7 @@ exit: } -int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options, +int mysql_create_db(THD *thd, const Lex_ident_db &db, DDL_options_st options, const Schema_specification_st *create_info) { DBUG_ASSERT(create_info->default_table_charset); @@ -959,7 +960,7 @@ int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options, } -bool mysql_alter_db(THD *thd, const LEX_CSTRING *db, +bool mysql_alter_db(THD *thd, const Lex_ident_db &db, const Schema_specification_st *create_info) { DBUG_ASSERT(create_info->default_table_charset); @@ -1007,14 +1008,14 @@ void drop_database_objects(THD *thd, const LEX_CSTRING *path, debug_crash_here("ddl_log_drop_before_drop_db_routines"); - query_cache_invalidate1(thd, db->str); + query_cache_invalidate1(thd, *db); if (!rm_mysql_schema) { tmp_disable_binlog(thd); - (void) sp_drop_db_routines(thd, db->str); /* @todo Do not ignore errors */ + (void) sp_drop_db_routines(thd, *db); /* @todo Do not ignore errors */ #ifdef HAVE_EVENT_SCHEDULER - Events::drop_schema_events(thd, db->str); + Events::drop_schema_events(thd, *db); #endif reenable_binlog(thd); } @@ -1038,7 +1039,7 @@ void drop_database_objects(THD *thd, const LEX_CSTRING *path, */ static bool -mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, +mysql_rm_db_internal(THD *thd, const Lex_ident_db &db, bool if_exists, bool silent) { ulong deleted_tables= 0; @@ -1050,33 +1051,30 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, TABLE_LIST *table; DDL_LOG_STATE ddl_log_state; Drop_table_error_handler err_handler; - LEX_CSTRING rm_db; - char db_tmp[SAFE_NAME_LEN+1]; - const char *dbnorm; DBUG_ENTER("mysql_rm_db"); - dbnorm= normalize_db_name(db->str, db_tmp, sizeof(db_tmp)); - lex_string_set(&rm_db, dbnorm); + const DBNameBuffer dbnorm_buffer(db, lower_case_table_names); + Lex_ident_db_normalized dbnorm(dbnorm_buffer.to_lex_cstring()); bzero(&ddl_log_state, sizeof(ddl_log_state)); if (lock_schema_name(thd, dbnorm)) DBUG_RETURN(true); - path_length= build_table_filename(path, sizeof(path) - 1, db->str, "", "", 0); + path_length= build_table_filename(path, sizeof(path) - 1, db.str, "", "", 0); /* See if the directory exists */ if (!(dirp= my_dir(path,MYF(MY_DONT_SORT)))) { if (!if_exists) { - my_error(ER_DB_DROP_EXISTS, MYF(0), db->str); + my_error(ER_DB_DROP_EXISTS, MYF(0), db.str); DBUG_RETURN(true); } else { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DB_DROP_EXISTS, ER_THD(thd, ER_DB_DROP_EXISTS), - db->str); + db.str); error= false; goto update_binlog; } @@ -1090,7 +1088,7 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, This check is only needed if we are dropping the "mysql" database. */ if ((rm_mysql_schema= - (my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db->str) == 0))) + (my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db.str) == 0))) { for (table= tables; table; table= table->next_local) if (check_if_log_table(table, TRUE, "DROP")) @@ -1126,15 +1124,15 @@ mysql_rm_db_internal(THD *thd, const LEX_CSTRING *db, bool if_exists, thd->push_internal_handler(&err_handler); if (!thd->killed && !(tables && - mysql_rm_table_no_locks(thd, tables, &rm_db, &ddl_log_state, true, false, + mysql_rm_table_no_locks(thd, tables, &dbnorm, &ddl_log_state, true, false, true, false, true, false))) { debug_crash_here("ddl_log_drop_after_drop_tables"); LEX_CSTRING cpath{ path, path_length}; - ddl_log_drop_db(&ddl_log_state, &rm_db, &cpath); + ddl_log_drop_db(&ddl_log_state, &dbnorm, &cpath); - drop_database_objects(thd, &cpath, &rm_db, rm_mysql_schema); + drop_database_objects(thd, &cpath, &dbnorm, rm_mysql_schema); /* Now remove the db.opt file. @@ -1175,7 +1173,7 @@ update_binlog: bzero(&ddl_log, sizeof(ddl_log)); ddl_log.query= { C_STRING_WITH_LEN("DROP") }; ddl_log.org_storage_engine_name= { C_STRING_WITH_LEN("DATABASE") }; - ddl_log.org_database= *db; + ddl_log.org_database= db; backup_log_ddl(&ddl_log); } @@ -1199,8 +1197,8 @@ update_binlog: database" and not the threads current database, which is the default. */ - qinfo.db = db->str; - qinfo.db_len = (uint32)db->length; + qinfo.db = db.str; + qinfo.db_len = (uint32) db.length; /* These DDL methods and logging are protected with the exclusive @@ -1251,7 +1249,7 @@ update_binlog: These DDL methods and logging are protected with the exclusive metadata lock on the schema. */ - if (write_to_binlog(thd, query, (uint)(query_pos -1 - query), db->str, db->length)) + if (write_to_binlog(thd, query, (uint)(query_pos -1 - query), db.str, db.length)) { error= true; goto exit; @@ -1273,8 +1271,8 @@ update_binlog: debug_crash_here("ddl_log_drop_before_binlog"); thd->binlog_xid= thd->query_id; ddl_log_update_xid(&ddl_log_state, thd->binlog_xid); - res= write_to_binlog(thd, query, (uint)(query_pos -1 - query), db->str, - db->length); + res= write_to_binlog(thd, query, (uint)(query_pos -1 - query), db.str, + db.length); thd->binlog_xid= 0; debug_crash_here("ddl_log_drop_after_binlog"); if (res) @@ -1293,7 +1291,7 @@ exit: SELECT DATABASE() in the future). For this we free() thd->db and set it to 0. */ - if (unlikely(thd->db.str && cmp_db_names(&thd->db, db) && !error)) + if (unlikely(thd->db.str && cmp_db_names(&thd->db, &db) && !error)) { mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server); thd->session_tracker.current_schema.mark_as_changed(thd); @@ -1304,7 +1302,7 @@ end: } -bool mysql_rm_db(THD *thd, const LEX_CSTRING *db, bool if_exists) +bool mysql_rm_db(THD *thd, const Lex_ident_db &db, bool if_exists) { if (thd->slave_thread && slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) @@ -1314,12 +1312,11 @@ bool mysql_rm_db(THD *thd, const LEX_CSTRING *db, bool if_exists) static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp, - const char *dbname, + const Lex_ident_db_normalized &db, const char *path, TABLE_LIST **tables) { char filePath[FN_REFLEN]; - LEX_CSTRING db= { dbname, strlen(dbname) }; TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global; DBUG_ENTER("find_db_tables_and_rm_known_files"); DBUG_PRINT("enter",("path: %s", path)); @@ -1700,6 +1697,7 @@ static void backup_current_db_name(THD *thd, uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, bool force_switch) { + DBNameBuffer new_db_buff; LEX_CSTRING new_db_file_name; Security_context *sctx= thd->security_ctx; @@ -1742,19 +1740,10 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, goto done; } - /* - Now we need to make a copy because check_db_name requires a - non-constant argument. Actually, it takes database file name. - - TODO: fix check_db_name(). - */ - - new_db_file_name.str= my_strndup(key_memory_THD_db, new_db_name->str, - new_db_name->length, MYF(MY_WME)); - new_db_file_name.length= new_db_name->length; - - if (new_db_file_name.str == NULL) - DBUG_RETURN(ER_OUT_OF_RESOURCES); /* the error is set */ + new_db_file_name= lower_case_table_names == 1 ? + new_db_buff.copy_casedn(&my_charset_utf8mb3_general_ci, + *new_db_name).to_lex_cstring() : + *new_db_name; /* NOTE: if check_db_name() fails, we should throw an error in any case, @@ -1766,11 +1755,8 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, The cast below ok here as new_db_file_name was just allocated */ - if (check_db_name((LEX_STRING*) &new_db_file_name)) + if (Lex_ident_fs(new_db_file_name).check_db_name_with_error()) { - my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str); - my_free(const_cast(new_db_file_name.str)); - if (force_switch) mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server); @@ -1800,7 +1786,6 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, new_db_file_name.str); general_log_print(thd, COM_INIT_DB, ER_THD(thd, ER_DBACCESS_DENIED_ERROR), sctx->priv_user, sctx->priv_host, new_db_file_name.str); - my_free(const_cast(new_db_file_name.str)); DBUG_RETURN(ER_DBACCESS_DENIED_ERROR); } #endif @@ -1817,8 +1802,6 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, ER_BAD_DB_ERROR, ER_THD(thd, ER_BAD_DB_ERROR), new_db_file_name.str); - my_free(const_cast(new_db_file_name.str)); - /* Change db to NULL. */ mysql_change_db_impl(thd, NULL, NO_ACL, thd->variables.collation_server); @@ -1831,7 +1814,6 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, /* Report an error and free new_db_file_name. */ my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str); - my_free(const_cast(new_db_file_name.str)); /* The operation failed. */ @@ -1839,14 +1821,23 @@ uint mysql_change_db(THD *thd, const LEX_CSTRING *new_db_name, } } + db_default_cl= get_default_db_collation(thd, new_db_file_name.str); + /* + new_db_file_name allocated memory on the stack. + mysql_change_db_impl() expects a my_alloc-ed memory. NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD attributes and will be freed in THD::~THD(). */ - - db_default_cl= get_default_db_collation(thd, new_db_file_name.str); - - mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl); + if (const char *tmp= my_strndup(key_memory_THD_db, + new_db_file_name.str, + new_db_file_name.length, MYF(MY_WME))) + { + LEX_CSTRING new_db_malloced({tmp, new_db_file_name.length}); + mysql_change_db_impl(thd, &new_db_malloced, db_access, db_default_cl); + } + else + DBUG_RETURN(ER_OUT_OF_RESOURCES); /* the error is set */ done: thd->session_tracker.current_schema.mark_as_changed(thd); @@ -1907,7 +1898,7 @@ bool mysql_opt_change_db(THD *thd, @return 0 on success, 1 on error */ -bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) +bool mysql_upgrade_db(THD *thd, const Lex_ident_db &old_db) { bool error= 0, change_to_newdb= 0; char path[FN_REFLEN+16]; @@ -1916,11 +1907,11 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) MY_DIR *dirp; TABLE_LIST *table_list; SELECT_LEX *sl= thd->lex->current_select; - LEX_CSTRING new_db; + Lex_ident_db new_db; DBUG_ENTER("mysql_upgrade_db"); - if ((old_db->length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) || - (strncmp(old_db->str, + if ((old_db.length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) || + (strncmp(old_db.str, MYSQL50_TABLE_NAME_PREFIX, MYSQL50_TABLE_NAME_PREFIX_LENGTH) != 0)) { @@ -1931,12 +1922,11 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) } /* `#mysql50#` converted to encoded `` */ - new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH; - new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH; + new_db= Lex_ident_db(old_db.str + MYSQL50_TABLE_NAME_PREFIX_LENGTH, + old_db.length - MYSQL50_TABLE_NAME_PREFIX_LENGTH); - char dbnorm_buffer_old[SAFE_NAME_LEN + 1]; - const char *old_dbnorm= normalize_db_name(old_db->str, dbnorm_buffer_old, - sizeof(dbnorm_buffer_old)); + const DBNameBuffer dbnorm_buffer_old(old_db, lower_case_table_names); + Lex_ident_db_normalized old_dbnorm(dbnorm_buffer_old.to_lex_cstring()); /* Lock the old name, the new name will be locked by mysql_create_db().*/ if (lock_schema_name(thd, old_dbnorm)) @@ -1946,25 +1936,25 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) Let's remember if we should do "USE newdb" afterwards. thd->db will be cleared in mysql_rename_db() */ - if (thd->db.str && !cmp(&thd->db, old_db)) + if (thd->db.str && !cmp(&thd->db, &old_db)) change_to_newdb= 1; build_table_filename(path, sizeof(path)-1, - old_db->str, "", MY_DB_OPT_FILE, 0); + old_db.str, "", MY_DB_OPT_FILE, 0); if ((load_db_opt(thd, path, &create_info))) create_info.default_table_charset= thd->variables.collation_server; - length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0); + length= build_table_filename(path, sizeof(path)-1, old_db.str, "", "", 0); if (length && path[length-1] == FN_LIBCHAR) path[length-1]=0; // remove ending '\' if (unlikely((error= my_access(path,F_OK)))) { - my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str); + my_error(ER_BAD_DB_ERROR, MYF(0), old_db.str); goto exit; } /* Step1: Create the new database */ - if (unlikely((error= mysql_create_db_internal(thd, &new_db, + if (unlikely((error= mysql_create_db_internal(thd, new_db, DDL_options(), &create_info, 1)))) goto exit; @@ -1990,7 +1980,7 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) table_str.length= filename_to_tablename(file->name, tname, sizeof(tname)-1); table_str.str= (char*) thd->memdup(tname, table_str.length + 1); - Table_ident *old_ident= new Table_ident(thd, old_db, &table_str, 0); + Table_ident *old_ident= new Table_ident(thd, &old_db, &table_str, 0); Table_ident *new_ident= new Table_ident(thd, &new_db, &table_str, 0); if (!old_ident || !new_ident || !sl->add_table_to_list(thd, old_ident, NULL, @@ -2075,7 +2065,7 @@ bool mysql_upgrade_db(THD *thd, const LEX_CSTRING *old_db) /* pass empty file name, and file->name as extension to avoid encoding */ build_table_filename(oldname, sizeof(oldname)-1, - old_db->str, "", file->name, 0); + old_db.str, "", file->name, 0); build_table_filename(newname, sizeof(newname)-1, new_db.str, "", file->name, 0); mysql_file_rename(key_file_misc, oldname, newname, MYF(MY_WME)); @@ -2152,14 +2142,3 @@ bool check_db_dir_existence(const char *db_name) mysql_rwlock_unlock(&rmdir_lock); return ret; } - - -const char *normalize_db_name(const char *db, char *buffer, size_t buffer_size) -{ - DBUG_ASSERT(buffer_size > 1); - if (!lower_case_table_names) - return db; - strmake(buffer, db, buffer_size - 1); - my_casedn_str(system_charset_info, buffer); - return buffer; -} -- cgit v1.2.3