Loading sql/mysql_priv.h +1 −1 Original line number Diff line number Diff line Loading @@ -757,7 +757,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem, bool *refresh, uint flags); TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table); bool reopen_name_locked_table(THD* thd, TABLE_LIST* table); TABLE *find_locked_table(THD *thd, const char *db,const char *table_name); bool reopen_table(TABLE *table,bool locked); bool reopen_tables(THD *thd,bool get_locks,bool in_refresh); Loading sql/sql_base.cc +42 −18 Original line number Diff line number Diff line Loading @@ -976,32 +976,57 @@ void wait_for_refresh(THD *thd) } TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) /* Open table which is already name-locked by this thread. SYNOPSIS reopen_name_locked_table() thd Thread handle table_list TABLE_LIST object for table to be open, TABLE_LIST::table member should point to TABLE object which was used for name-locking. NOTE This function assumes that its caller already acquired LOCK_open mutex. RETURN VALUE FALSE - Success TRUE - Error */ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) { DBUG_ENTER("reopen_name_locked_table"); if (thd->killed) DBUG_RETURN(0); TABLE *table; TABLE *table= table_list->table; TABLE_SHARE *share; if (!(table = table_list->table)) DBUG_RETURN(0); char* db = thd->db ? thd->db : table_list->db; char *db= table_list->db; char *table_name= table_list->table_name; char key[MAX_DBKEY_LENGTH]; uint key_length; TABLE orig_table; DBUG_ENTER("reopen_name_locked_table"); safe_mutex_assert_owner(&LOCK_open); if (thd->killed || !table) DBUG_RETURN(TRUE); orig_table= *table; key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; pthread_mutex_lock(&LOCK_open); if (open_unireg_entry(thd, table, db, table_name, table_name, 0, thd->mem_root) || !(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key, key_length))) { delete table->triggers; closefrm(table); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); intern_close_table(table); /* If there was an error during opening of table (for example if it does not exist) '*table' object can be wiped out. To be able properly release name-lock in this case we should restore this object to its original state. */ *table= orig_table; DBUG_RETURN(TRUE); } share= table->s; Loading @@ -1011,7 +1036,6 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) share->flush_version=0; table->in_use = thd; check_unused(); pthread_mutex_unlock(&LOCK_open); table->next = thd->open_tables; thd->open_tables = table; table->tablenr=thd->current_tablenr++; Loading @@ -1021,7 +1045,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= share->keys_in_use; table->used_keys= share->keys_for_keyread; DBUG_RETURN(table); DBUG_RETURN(FALSE); } Loading sql/sql_table.cc +13 −6 Original line number Diff line number Diff line Loading @@ -1951,7 +1951,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, char* backup_dir= thd->lex->backup_dir; char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char* table_name= table->table_name; char* db = thd->db ? thd->db : table->db; char* db= table->db; if (fn_format_relative_to_data_home(src_path, table_name, backup_dir, reg_ext)) Loading Loading @@ -1987,12 +1987,15 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, Now we should be able to open the partially restored table to finish the restore in the handler later on */ if (!(table->table = reopen_name_locked_table(thd, table))) { pthread_mutex_lock(&LOCK_open); if (reopen_name_locked_table(thd, table)) { unlock_table_name(thd, table); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed to open partially restored table")); } pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } Loading Loading @@ -2089,12 +2092,16 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ if (!(table_list->table = reopen_name_locked_table(thd, table_list))) { pthread_mutex_lock(&LOCK_open); if (reopen_name_locked_table(thd, table_list)) { unlock_table_name(thd, table_list); pthread_mutex_unlock(&LOCK_open); error= send_check_errmsg(thd, table_list, "repair", "Failed to open partially repaired table"); goto end; } pthread_mutex_unlock(&LOCK_open); end: if (table == &tmp_table) Loading sql/sql_trigger.cc +39 −37 Original line number Diff line number Diff line Loading @@ -103,8 +103,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { TABLE *table; bool result= 0; bool result= TRUE; DBUG_ENTER("mysql_create_or_drop_trigger"); /* Loading @@ -119,9 +118,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* We should have only one table in table list. */ DBUG_ASSERT(tables->next_global == 0); if (!(table= open_ltable(thd, tables, tables->lock_type))) DBUG_RETURN(TRUE); /* TODO: We should check if user has TRIGGER privilege for table here. Now we just require SUPER privilege for creating/dropping because Loading @@ -131,27 +127,23 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) DBUG_RETURN(TRUE); /* We do not allow creation of triggers on temporary tables. We also don't allow creation of triggers on views but fulfilment of this restriction is guaranteed by open_ltable(). It is better to have this check here than do it in Table_triggers_list::create_trigger() and mess with table cache. There is no DETERMINISTIC clause for triggers, so can't check it. But a trigger can in theory be used to do nasty things (if it supported DROP for example) so we do the check for privileges. For now there is already a stronger test right above; but when this stronger test will be removed, the test below will hold. */ if (table->s->tmp_table != NO_TMP_TABLE) if (!trust_routine_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); } if (!table->triggers) { if (!create) /* We do not allow creation of triggers on temporary tables. */ if (create && find_temporary_table(thd, tables->db, tables->table_name)) { my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0)); DBUG_RETURN(TRUE); } if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); DBUG_RETURN(TRUE); } Loading @@ -161,31 +153,41 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) again until we are done. (Acquiring LOCK_open is not enough because global read lock is held without helding LOCK_open). */ if (wait_if_global_read_lock(thd, 0, 0)) if (wait_if_global_read_lock(thd, 0, 1)) DBUG_RETURN(TRUE); /* There is no DETERMINISTIC clause for triggers, so can't check it. But a trigger can in theory be used to do nasty things (if it supported DROP for example) so we do the check for privileges. For now there is already a stronger test above (see start of the function); but when this stronger test will be removed, the test below will hold. */ if (!trust_routine_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) VOID(pthread_mutex_lock(&LOCK_open)); if (lock_table_names(thd, tables)) goto end; /* We also don't allow creation of triggers on views. */ tables->required_type= FRMTYPE_TABLE; if (reopen_name_locked_table(thd, tables)) { my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); DBUG_RETURN(TRUE); unlock_table_name(thd, tables); goto end; } table= tables->table; if (!table->triggers) { if (!create) { my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); goto end; } if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) goto end; } VOID(pthread_mutex_lock(&LOCK_open)); result= (create ? table->triggers->create_trigger(thd, tables): table->triggers->drop_trigger(thd, tables)); /* It is sensible to invalidate table in any case */ close_cached_table(thd, table); end: VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); Loading Loading
sql/mysql_priv.h +1 −1 Original line number Diff line number Diff line Loading @@ -757,7 +757,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem, bool *refresh, uint flags); TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table); bool reopen_name_locked_table(THD* thd, TABLE_LIST* table); TABLE *find_locked_table(THD *thd, const char *db,const char *table_name); bool reopen_table(TABLE *table,bool locked); bool reopen_tables(THD *thd,bool get_locks,bool in_refresh); Loading
sql/sql_base.cc +42 −18 Original line number Diff line number Diff line Loading @@ -976,32 +976,57 @@ void wait_for_refresh(THD *thd) } TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) /* Open table which is already name-locked by this thread. SYNOPSIS reopen_name_locked_table() thd Thread handle table_list TABLE_LIST object for table to be open, TABLE_LIST::table member should point to TABLE object which was used for name-locking. NOTE This function assumes that its caller already acquired LOCK_open mutex. RETURN VALUE FALSE - Success TRUE - Error */ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) { DBUG_ENTER("reopen_name_locked_table"); if (thd->killed) DBUG_RETURN(0); TABLE *table; TABLE *table= table_list->table; TABLE_SHARE *share; if (!(table = table_list->table)) DBUG_RETURN(0); char* db = thd->db ? thd->db : table_list->db; char *db= table_list->db; char *table_name= table_list->table_name; char key[MAX_DBKEY_LENGTH]; uint key_length; TABLE orig_table; DBUG_ENTER("reopen_name_locked_table"); safe_mutex_assert_owner(&LOCK_open); if (thd->killed || !table) DBUG_RETURN(TRUE); orig_table= *table; key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; pthread_mutex_lock(&LOCK_open); if (open_unireg_entry(thd, table, db, table_name, table_name, 0, thd->mem_root) || !(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key, key_length))) { delete table->triggers; closefrm(table); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); intern_close_table(table); /* If there was an error during opening of table (for example if it does not exist) '*table' object can be wiped out. To be able properly release name-lock in this case we should restore this object to its original state. */ *table= orig_table; DBUG_RETURN(TRUE); } share= table->s; Loading @@ -1011,7 +1036,6 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) share->flush_version=0; table->in_use = thd; check_unused(); pthread_mutex_unlock(&LOCK_open); table->next = thd->open_tables; thd->open_tables = table; table->tablenr=thd->current_tablenr++; Loading @@ -1021,7 +1045,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= share->keys_in_use; table->used_keys= share->keys_for_keyread; DBUG_RETURN(table); DBUG_RETURN(FALSE); } Loading
sql/sql_table.cc +13 −6 Original line number Diff line number Diff line Loading @@ -1951,7 +1951,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, char* backup_dir= thd->lex->backup_dir; char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char* table_name= table->table_name; char* db = thd->db ? thd->db : table->db; char* db= table->db; if (fn_format_relative_to_data_home(src_path, table_name, backup_dir, reg_ext)) Loading Loading @@ -1987,12 +1987,15 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, Now we should be able to open the partially restored table to finish the restore in the handler later on */ if (!(table->table = reopen_name_locked_table(thd, table))) { pthread_mutex_lock(&LOCK_open); if (reopen_name_locked_table(thd, table)) { unlock_table_name(thd, table); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed to open partially restored table")); } pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } Loading Loading @@ -2089,12 +2092,16 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ if (!(table_list->table = reopen_name_locked_table(thd, table_list))) { pthread_mutex_lock(&LOCK_open); if (reopen_name_locked_table(thd, table_list)) { unlock_table_name(thd, table_list); pthread_mutex_unlock(&LOCK_open); error= send_check_errmsg(thd, table_list, "repair", "Failed to open partially repaired table"); goto end; } pthread_mutex_unlock(&LOCK_open); end: if (table == &tmp_table) Loading
sql/sql_trigger.cc +39 −37 Original line number Diff line number Diff line Loading @@ -103,8 +103,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { TABLE *table; bool result= 0; bool result= TRUE; DBUG_ENTER("mysql_create_or_drop_trigger"); /* Loading @@ -119,9 +118,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* We should have only one table in table list. */ DBUG_ASSERT(tables->next_global == 0); if (!(table= open_ltable(thd, tables, tables->lock_type))) DBUG_RETURN(TRUE); /* TODO: We should check if user has TRIGGER privilege for table here. Now we just require SUPER privilege for creating/dropping because Loading @@ -131,27 +127,23 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) DBUG_RETURN(TRUE); /* We do not allow creation of triggers on temporary tables. We also don't allow creation of triggers on views but fulfilment of this restriction is guaranteed by open_ltable(). It is better to have this check here than do it in Table_triggers_list::create_trigger() and mess with table cache. There is no DETERMINISTIC clause for triggers, so can't check it. But a trigger can in theory be used to do nasty things (if it supported DROP for example) so we do the check for privileges. For now there is already a stronger test right above; but when this stronger test will be removed, the test below will hold. */ if (table->s->tmp_table != NO_TMP_TABLE) if (!trust_routine_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) { my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); my_error(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, MYF(0)); DBUG_RETURN(TRUE); } if (!table->triggers) { if (!create) /* We do not allow creation of triggers on temporary tables. */ if (create && find_temporary_table(thd, tables->db, tables->table_name)) { my_message(ER_TRG_DOES_NOT_EXIST, ER(ER_TRG_DOES_NOT_EXIST), MYF(0)); DBUG_RETURN(TRUE); } if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias); DBUG_RETURN(TRUE); } Loading @@ -161,31 +153,41 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) again until we are done. (Acquiring LOCK_open is not enough because global read lock is held without helding LOCK_open). */ if (wait_if_global_read_lock(thd, 0, 0)) if (wait_if_global_read_lock(thd, 0, 1)) DBUG_RETURN(TRUE); /* There is no DETERMINISTIC clause for triggers, so can't check it. But a trigger can in theory be used to do nasty things (if it supported DROP for example) so we do the check for privileges. For now there is already a stronger test above (see start of the function); but when this stronger test will be removed, the test below will hold. */ if (!trust_routine_creators && mysql_bin_log.is_open() && !(thd->security_ctx->master_access & SUPER_ACL)) VOID(pthread_mutex_lock(&LOCK_open)); if (lock_table_names(thd, tables)) goto end; /* We also don't allow creation of triggers on views. */ tables->required_type= FRMTYPE_TABLE; if (reopen_name_locked_table(thd, tables)) { my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); DBUG_RETURN(TRUE); unlock_table_name(thd, tables); goto end; } table= tables->table; if (!table->triggers) { if (!create) { my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); goto end; } if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table))) goto end; } VOID(pthread_mutex_lock(&LOCK_open)); result= (create ? table->triggers->create_trigger(thd, tables): table->triggers->drop_trigger(thd, tables)); /* It is sensible to invalidate table in any case */ close_cached_table(thd, table); end: VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); Loading