summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_base.cc60
-rw-r--r--sql/sql_table.cc19
-rw-r--r--sql/sql_trigger.cc76
4 files changed, 95 insertions, 62 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c80e457d2bb..ef62826809b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 51b9fe43796..37af9975ae1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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= 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");
- char* db = thd->db ? thd->db : table_list->db;
- char* table_name = table_list->table_name;
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
+ 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;
@@ -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++;
@@ -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);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 0bc1537235b..1dc952ab2e9 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1950,8 +1950,8 @@ 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* table_name= table->table_name;
+ char* db= table->db;
if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
reg_ext))
@@ -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))
{
- pthread_mutex_lock(&LOCK_open);
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);
}
@@ -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))
{
- pthread_mutex_lock(&LOCK_open);
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)
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index df8de59508d..dbad8dcffb5 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -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");
/*
@@ -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
@@ -131,28 +127,24 @@ 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)
+ /* We do not allow creation of triggers on temporary tables. */
+ if (create && find_temporary_table(thd, tables->db, tables->table_name))
{
- if (!create)
- {
- 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)))
- DBUG_RETURN(TRUE);
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ DBUG_RETURN(TRUE);
}
/*
@@ -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);