diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0d67c25cee5..17133474190 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2441,6 +2441,24 @@ mysql_execute_command(THD *thd) lex->create_info.default_table_charset= lex->create_info.table_charset; lex->create_info.table_charset= 0; } + /* + The create-select command will open and read-lock the select table + and then create, open and write-lock the new table. If a global + read lock steps in, we get a deadlock. The write lock waits for + the global read lock, while the global read lock waits for the + select table to be closed. So we wait until the global readlock is + gone before starting both steps. Note that + wait_if_global_read_lock() sets a protection against a new global + read lock when it succeeds. This needs to be released by + start_waiting_global_read_lock(). We protect the normal CREATE + TABLE in the same way. That way we avoid that a new table is + created during a gobal read lock. + */ + if (wait_if_global_read_lock(thd, 0, 1)) + { + res= -1; + goto unsent_create_error; + } if (select_lex->item_list.elements) // With select { select_result *result; @@ -2491,13 +2509,17 @@ mysql_execute_command(THD *thd) if (!res) send_ok(thd); } + /* + Release the protection against the global read lock and wake + everyone, who might want to set a global read lock. + */ + start_waiting_global_read_lock(thd); // put tables back for PS rexecuting tables= lex->link_first_table_back(tables, create_table, create_table_local); break; - res= 1; //error reported unsent_create_error: // put tables back for PS rexecuting tables= lex->link_first_table_back(tables, create_table, @@ -2821,8 +2843,8 @@ unsent_create_error: TABLE *table= tables->table; /* Skip first table, which is the table we are inserting in */ - lex->select_lex.table_list.first= (byte*) first_local_table->next; - tables= (TABLE_LIST *) lex->select_lex.table_list.first; + select_lex->table_list.first= (byte*) first_local_table->next; + tables= (TABLE_LIST *) select_lex->table_list.first; first_local_table->next= 0; if (!(res= mysql_prepare_insert(thd, tables, first_local_table, @@ -3670,6 +3692,14 @@ error: thd->lock= 0; } DBUG_VOID_RETURN; + + error1: + /* + Release the protection against the global read lock and wake + everyone, who might want to set a global read lock. + */ + start_waiting_global_read_lock(thd); + DBUG_VOID_RETURN; } @@ -5392,6 +5422,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) 1 error (message is sent to user) -1 error (message is not sent to user) */ + int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) { DBUG_ENTER("multi_delete_precheck"); |