diff --git a/sql/handler.cc b/sql/handler.cc index c7a0b4a91f4b5..8b80cfdd42f42 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6421,7 +6421,8 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin, bool ha_table_exists(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, LEX_CUSTRING *table_id, LEX_CSTRING *partition_engine_name, - handlerton **hton, bool *is_sequence) + handlerton **hton, bool *is_sequence, + HA_CREATE_INFO *ha_create_info) { handlerton *dummy; bool dummy2; @@ -6475,8 +6476,17 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, retry_from_frm: #endif char path[FN_REFLEN + 1]; - size_t path_len = build_table_filename(path, sizeof(path) - 1, - db->str, table_name->str, "", 0); + size_t path_len= 0; + if (ha_create_info) + { + path_len= ha_create_info->table_path.length; + strncpy(path, ha_create_info->table_path.str, path_len); + } + else + /* this happens for views */ + path_len = build_table_filename(path, sizeof(path) - 1, + db->str, table_name->str, "", 0); + st_discover_existence_args args= {path, path_len, db->str, table_name->str, 0, true}; if (file_ext_exists(path, path_len, reg_ext)) diff --git a/sql/handler.h b/sql/handler.h index 6501b2ce4a548..1e66bdb140fe8 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2325,12 +2325,14 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st, { /* TODO: remove after MDEV-20865 */ Alter_info *alter_info; - + bool table_exists; + LEX_CSTRING table_path; void init() { Table_scope_and_contents_source_st::init(); Schema_specification_st::init(); alter_info= NULL; + table_exists= false; } ulong table_options_with_row_type() { @@ -5592,7 +5594,8 @@ bool ha_table_exists(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *table_name, LEX_CUSTRING *table_version= 0, LEX_CSTRING *partition_engine_name= 0, - handlerton **hton= 0, bool *is_sequence= 0); + handlerton **hton= 0, bool *is_sequence= 0, + HA_CREATE_INFO *ha_create_info= 0); bool ha_check_if_updates_are_ignored(THD *thd, handlerton *hton, const char *op); #endif /* MYSQL_SERVER */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e95494fd91747..84790e8dcdcf4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3455,8 +3455,9 @@ Open_table_context::recover_from_failed_open() case OT_ADD_HISTORY_PARTITION: DEBUG_SYNC(m_thd, "add_history_partition"); if (!m_thd->locked_tables_mode) - result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table, - NULL, get_timeout(), 0); + result= lock_table_names(m_thd, m_thd->lex->create_info, + m_thd->lex->create_info, m_failed_table, + NULL, get_timeout(), 0); else { DBUG_ASSERT(!result); @@ -4275,6 +4276,7 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, static bool upgrade_lock_if_not_exists(THD *thd, const DDL_options_st &create_info, + HA_CREATE_INFO &ha_create_info, TABLE_LIST *create_table, ulong lock_wait_timeout) { @@ -4284,9 +4286,14 @@ static bool upgrade_lock_if_not_exists(THD *thd, thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) { DEBUG_SYNC(thd,"create_table_before_check_if_exists"); - if (!create_info.or_replace() && - ha_table_exists(thd, &create_table->db, &create_table->table_name, - NULL, NULL, &create_table->db_type)) + /* Mark table as existed for CREATE to optimize calls of ha_table_exists + and store table path. We should not change original default handlerton + ha_create_info.db_type from `ha_table_exists`. + */ + ha_create_info.table_exists= ha_table_exists(thd, &create_table->db, &create_table->table_name, + NULL, NULL, &create_table->db_type, + NULL, &ha_create_info); + if (!create_info.or_replace() && ha_create_info.table_exists) { if (create_info.if_not_exists()) { @@ -4339,7 +4346,7 @@ static bool upgrade_lock_if_not_exists(THD *thd, */ bool -lock_table_names(THD *thd, const DDL_options_st &options, +lock_table_names(THD *thd, const DDL_options_st &options, HA_CREATE_INFO &ha_opt, TABLE_LIST *tables_start, TABLE_LIST *tables_end, ulong lock_wait_timeout, uint flags) { @@ -4385,12 +4392,17 @@ lock_table_names(THD *thd, const DDL_options_st &options, if (mdl_requests.is_empty()) DBUG_RETURN(FALSE); - + char path[FN_REFLEN + 1]; + ha_opt.table_path.length= build_table_filename(path, FN_REFLEN - 1, + tables_start->db.str, + tables_start->table_name.str, + "", 0); + lex_string_set3(&ha_opt.table_path, path, ha_opt.table_path.length); if (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) { DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) || - upgrade_lock_if_not_exists(thd, options, tables_start, + upgrade_lock_if_not_exists(thd, options, ha_opt, tables_start, lock_wait_timeout)); } @@ -4403,7 +4415,7 @@ lock_table_names(THD *thd, const DDL_options_st &options, mdl_savepoint= thd->mdl_context.mdl_savepoint(); while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) && - !upgrade_lock_if_not_exists(thd, options, tables_start, + !upgrade_lock_if_not_exists(thd, options, ha_opt, tables_start, lock_wait_timeout) && !thd->mdl_context.try_acquire_lock(&global_request)) { @@ -4528,7 +4540,7 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, @retval TRUE Error, reported. */ -bool open_tables(THD *thd, const DDL_options_st &options, +bool open_tables(THD *thd, const DDL_options_st &options, HA_CREATE_INFO &ha_opt, TABLE_LIST **start, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy) { @@ -4618,7 +4630,7 @@ bool open_tables(THD *thd, const DDL_options_st &options, else { TABLE_LIST *table; - if (lock_table_names(thd, options, *start, + if (lock_table_names(thd, options, ha_opt, *start, thd->lex->first_not_own_table(), ot_ctx.get_timeout(), flags)) { @@ -5186,7 +5198,7 @@ bool open_and_lock_internal_tables(TABLE *table, bool lock_table) TABLE_LIST *tmp= table->internal_tables; DML_prelocking_strategy prelocking_strategy; - if (open_tables(thd, thd->lex->create_info, &tmp, &counter, 0, + if (open_tables(thd, thd->lex->create_info, thd->lex->create_info, &tmp, &counter, 0, &prelocking_strategy)) goto err; @@ -5616,6 +5628,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, */ bool open_and_lock_tables(THD *thd, const DDL_options_st &options, + HA_CREATE_INFO &ha_opt, TABLE_LIST *tables, bool derived, uint flags, Prelocking_strategy *prelocking_strategy) @@ -5625,7 +5638,7 @@ bool open_and_lock_tables(THD *thd, const DDL_options_st &options, DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); - if (open_tables(thd, options, &tables, &counter, flags, prelocking_strategy)) + if (open_tables(thd, options, ha_opt, &tables, &counter, flags, prelocking_strategy)) goto err; DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", { diff --git a/sql/sql_base.h b/sql/sql_base.h index f285e28e2b55b..667c21bb769e1 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -248,7 +248,7 @@ int setup_ftfuncs(SELECT_LEX* select); void cleanup_ftfuncs(SELECT_LEX *select_lex); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); bool lock_table_names(THD *thd, const DDL_options_st &options, - TABLE_LIST *table_list, + HA_CREATE_INFO &ha_opt, TABLE_LIST *table_list, TABLE_LIST *table_list_end, ulong lock_wait_timeout, uint flags); static inline bool @@ -256,23 +256,23 @@ lock_table_names(THD *thd, TABLE_LIST *table_list, TABLE_LIST *table_list_end, ulong lock_wait_timeout, uint flags) { - return lock_table_names(thd, thd->lex->create_info, table_list, - table_list_end, lock_wait_timeout, flags); + return lock_table_names(thd, thd->lex->create_info, thd->lex->create_info, + table_list, table_list_end, lock_wait_timeout, flags); } bool open_tables(THD *thd, const DDL_options_st &options, - TABLE_LIST **tables, uint *counter, + HA_CREATE_INFO &ha_opt, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy); static inline bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy) { - return open_tables(thd, thd->lex->create_info, tables, counter, flags, - prelocking_strategy); + return open_tables(thd, thd->lex->create_info, thd->lex->create_info, + tables, counter, flags, prelocking_strategy); } /* open_and_lock_tables with optional derived handling */ bool open_and_lock_tables(THD *thd, const DDL_options_st &options, - TABLE_LIST *tables, + HA_CREATE_INFO &ha_opt, TABLE_LIST *tables, bool derived, uint flags, Prelocking_strategy *prelocking_strategy); static inline bool @@ -280,7 +280,7 @@ open_and_lock_tables(THD *thd, TABLE_LIST *tables, bool derived, uint flags, Prelocking_strategy *prelocking_strategy) { - return open_and_lock_tables(thd, thd->lex->create_info, + return open_and_lock_tables(thd, thd->lex->create_info, thd->lex->create_info, tables, derived, flags, prelocking_strategy); } /* simple open_and_lock_tables without derived handling for single table */ @@ -482,12 +482,12 @@ class Alter_table_prelocking_strategy : public Prelocking_strategy inline bool -open_tables(THD *thd, const DDL_options_st &options, +open_tables(THD *thd, const DDL_options_st &options, HA_CREATE_INFO &ha_opt, TABLE_LIST **tables, uint *counter, uint flags) { DML_prelocking_strategy prelocking_strategy; - return open_tables(thd, options, tables, counter, flags, + return open_tables(thd, options, ha_opt, tables, counter, flags, &prelocking_strategy); } inline bool @@ -495,8 +495,8 @@ open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags) { DML_prelocking_strategy prelocking_strategy; - return open_tables(thd, thd->lex->create_info, tables, counter, flags, - &prelocking_strategy); + return open_tables(thd, thd->lex->create_info, thd->lex->create_info, + tables, counter, flags, &prelocking_strategy); } inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, @@ -512,12 +512,13 @@ inline TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, /* open_and_lock_tables with derived handling */ inline bool open_and_lock_tables(THD *thd, const DDL_options_st &options, + HA_CREATE_INFO &ha_opt, TABLE_LIST *tables, bool derived, uint flags) { DML_prelocking_strategy prelocking_strategy; - return open_and_lock_tables(thd, options, tables, derived, flags, + return open_and_lock_tables(thd, options, ha_opt, tables, derived, flags, &prelocking_strategy); } inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, @@ -525,7 +526,7 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, { DML_prelocking_strategy prelocking_strategy; - return open_and_lock_tables(thd, thd->lex->create_info, + return open_and_lock_tables(thd, thd->lex->create_info, thd->lex->create_info, tables, derived, flags, &prelocking_strategy); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2c0f01a5a574d..5d19b5867f187 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4484,10 +4484,28 @@ int create_table_impl(THD *thd, goto err; } - handlerton *db_type; - if (!internal_tmp_table && - ha_table_exists(thd, &db, &table_name, - &create_info->org_tabledef_version, NULL, &db_type)) + handlerton *db_type= NULL; + bool tbl_exists= false; + /* This check is need in case OPT_REPLACE and OPT_IF_NOT_EXISTS ddl and LOCK, + for which there is no call of `lock_table_names` and `ha_table_exists`. + */ + if (options.or_replace() || options.if_not_exists()) + { + char path[FN_REFLEN + 1]; + create_info->table_path.length= build_table_filename(path, FN_REFLEN - 1, + db.str, + table_name.str, + "", 0); + lex_string_set3(&create_info->table_path, path, + create_info->table_path.length); + tbl_exists= ha_table_exists(thd, &db, &table_name, + &create_info->org_tabledef_version, + NULL, &db_type, NULL, create_info); + } + else + tbl_exists= create_info->table_exists; + + if (!internal_tmp_table && tbl_exists) { if (ha_check_if_updates_are_ignored(thd, db_type, "CREATE")) { @@ -4747,13 +4765,12 @@ int mysql_create_table_no_lock(THD *thd, { const LEX_CSTRING *alias= table_case_name(create_info, table_name); path_length= build_table_filename(path, sizeof(path) - 1, db->str, - alias->str, - "", 0); + alias->str,"", 0); // Check if we hit FN_REFLEN bytes along with file extension. if (path_length+reg_ext_length > FN_REFLEN) { my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(path)-1, - path); + path); return true; } } @@ -4893,7 +4910,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, /* Open or obtain an exclusive metadata lock on table being created */ create_table->db_type= 0; - result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0); + create_info->table_exists= false; + lex_string_set3(&create_info->table_path, "\0", FN_REFLEN); + result= open_and_lock_tables(thd, *create_info, *create_info, + create_table, FALSE, 0); thd->lex->create_info.options= save_thd_create_info_options; @@ -5368,7 +5388,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, properly isolated from all concurrent operations which matter. */ - res= open_tables(thd, *create_info, &thd->lex->query_tables, ¬_used, 0); + res= open_tables(thd, *create_info, *create_info, &thd->lex->query_tables, ¬_used, 0); if (res) { @@ -12946,7 +12966,7 @@ bool Sql_cmd_create_table_like::execute(THD *thd) goto end_with_restore_list; } - res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0); + res= open_and_lock_tables(thd, create_info, create_info, lex->query_tables, TRUE, 0); if (unlikely(res)) { /* Got error or warning. Set res to 1 if error */ @@ -12999,6 +13019,22 @@ bool Sql_cmd_create_table_like::execute(THD *thd) CREATE from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ + /* + Check here if the table is already being created, + since `create_table_impl()` will be called, + without inovking of `mysql_create_table()` that calls `ha_table_exists`. + */ + char path[FN_REFLEN + 1]; + create_info.table_path.length= build_table_filename(path, FN_REFLEN - 1, + create_table->db.str, + create_table->table_name.str, + "", 0); + lex_string_set3(&create_info.table_path, path, + create_info.table_path.length); + create_info.table_exists= ha_table_exists(thd, &create_table->db, + &create_table->table_name, + NULL, NULL, + &create_table->db_type); if (!(res= handle_select(thd, lex, result, 0))) { if (create_info.tmp_table())