summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc102
1 files changed, 83 insertions, 19 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ba5c2ebf484..169fe219263 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2337,17 +2337,37 @@ static void reset_one_shot_variables(THD *thd)
}
-/****************************************************************************
-** mysql_execute_command
-** Execute command saved in thd and current_lex->sql_command
-****************************************************************************/
+/*
+ Execute command saved in thd and current_lex->sql_command
+
+ SYNOPSIS
+ mysql_execute_command()
+ thd Thread handle
+
+ IMPLEMENTATION
+
+ Before every operation that can request a write lock for a table
+ wait if a global read lock exists. However do not wait if this
+ thread has locked tables already. No new locks can be requested
+ until the other locks are released. The thread that requests the
+ global read lock waits for write locked tables to become unlocked.
+
+ 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() after the operation.
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
bool
mysql_execute_command(THD *thd)
{
- bool res= FALSE;
- int result= 0;
- LEX *lex= thd->lex;
+ bool res= FALSE;
+ bool need_start_waiting= FALSE; // have protection against global read lock
+ int result= 0;
+ LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
SELECT_LEX *select_lex= &lex->select_lex;
/* first table of first SELECT_LEX */
@@ -2832,7 +2852,8 @@ mysql_execute_command(THD *thd)
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))
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
{
res= 1;
goto end_with_restore_list;
@@ -2857,7 +2878,7 @@ mysql_execute_command(THD *thd)
{
update_non_unique_table_error(create_table, "CREATE", duplicate);
res= 1;
- goto end_with_restart_wait;
+ goto end_with_restore_list;
}
}
/* If we create merge table, we have to test tables in merge, too */
@@ -2873,7 +2894,7 @@ mysql_execute_command(THD *thd)
{
update_non_unique_table_error(tab, "CREATE", duplicate);
res= 1;
- goto end_with_restart_wait;
+ goto end_with_restore_list;
}
}
}
@@ -2915,13 +2936,6 @@ mysql_execute_command(THD *thd)
send_ok(thd);
}
-end_with_restart_wait:
- /*
- 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 */
end_with_restore_list:
lex->link_first_table_back(create_table, link_to_local);
@@ -3039,6 +3053,13 @@ end_with_restore_list:
goto error;
else
{
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
+ }
+
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
@@ -3296,6 +3317,14 @@ end_with_restore_list:
break;
/* Skip first table, which is the table we are inserting in */
select_lex->context.table_list= first_table->next_local;
+
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
+ }
+
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
@@ -3319,6 +3348,14 @@ end_with_restore_list:
select_lex->options|= SELECT_NO_UNLOCK;
unit->set_limit(select_lex);
+
+ if (! thd->locked_tables &&
+ ! (need_start_waiting= ! wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
+ }
+
if (!(res= open_and_lock_tables(thd, all_tables)))
{
/* Skip first table, which is the table we are inserting in */
@@ -3395,6 +3432,14 @@ end_with_restore_list:
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
+
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
+ }
+
res = mysql_delete(thd, all_tables, select_lex->where,
&select_lex->order_list,
unit->select_limit_cnt, select_lex->options,
@@ -3408,6 +3453,13 @@ end_with_restore_list:
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
multi_delete *result;
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ {
+ res= 1;
+ break;
+ }
+
if ((res= multi_delete_precheck(thd, all_tables)))
break;
@@ -4974,10 +5026,22 @@ end_with_restore_list:
if (lex->sql_command != SQLCOM_CALL && lex->sql_command != SQLCOM_EXECUTE &&
uc_update_queries[lex->sql_command]<2)
thd->row_count_func= -1;
- DBUG_RETURN(res || thd->net.report_error);
+
+ goto end;
error:
- DBUG_RETURN(1);
+ res= TRUE;
+
+end:
+ if (need_start_waiting)
+ {
+ /*
+ 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_RETURN(res || thd->net.report_error);
}