Bug #14262: SP: DROP PROCEDURE|VIEW (maybe more) write to binlog too late \

	(race cond)

It was possible for one thread to interrupt a Data Definition Language 
statement and thereby get messages to the binlog out of order.  Consider:

Connection 1: Drop Foo x
Connection 2: Create or replace Foo x
Connection 2: Log "Create or replace Foo x"
Connection 1: Log "Drop Foo x"

Local end would have Foo x, but the replicated slaves would not.

The fix for this is to wrap all DDL and logging of a kind in the same mutex.  
Since we already use mutexes for the various parts of altering the server, 
this only entails moving the logging events down close to the action, inside 
the mutex protection.
parent 46b3997c
45143312u0Tz4r0wPXCbUKwdHa2jWA
45143b90ewOQuTW8-jrB3ZSAQvMRJw
45184588w9U72A6KX1hUFeAC4shSHA
45185df8mZbxfp85FbA0VxUXkmDewA
451b110a3ZV6MITl93ehXk2wxrbW7g
...@@ -660,6 +660,17 @@ db_drop_routine(THD *thd, int type, sp_name *name) ...@@ -660,6 +660,17 @@ db_drop_routine(THD *thd, int type, sp_name *name)
if (table->file->delete_row(table->record[0])) if (table->file->delete_row(table->record[0]))
ret= SP_DELETE_ROW_FAILED; ret= SP_DELETE_ROW_FAILED;
} }
if (ret == SP_OK)
{
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
close_thread_tables(thd); close_thread_tables(thd);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -695,6 +706,17 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) ...@@ -695,6 +706,17 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
if ((table->file->update_row(table->record[1],table->record[0]))) if ((table->file->update_row(table->record[1],table->record[0])))
ret= SP_WRITE_ROW_FAILED; ret= SP_WRITE_ROW_FAILED;
} }
if (ret == SP_OK)
{
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
close_thread_tables(thd); close_thread_tables(thd);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -773,6 +795,7 @@ print_field_values(THD *thd, TABLE *table, ...@@ -773,6 +795,7 @@ print_field_values(THD *thd, TABLE *table,
return SP_INTERNAL_ERROR; return SP_INTERNAL_ERROR;
} }
} }
return SP_OK; return SP_OK;
} }
......
...@@ -3005,9 +3005,22 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -3005,9 +3005,22 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
grant_option=TRUE; grant_option=TRUE;
thd->mem_root= old_root; thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock); pthread_mutex_unlock(&acl_cache->lock);
if (!result) /* success */
{
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
if (!result)
if (!result) /* success */
send_ok(thd); send_ok(thd);
/* Tables are automatically closed */ /* Tables are automatically closed */
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -3168,9 +3181,21 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, ...@@ -3168,9 +3181,21 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
grant_option=TRUE; grant_option=TRUE;
thd->mem_root= old_root; thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock); pthread_mutex_unlock(&acl_cache->lock);
if (!result && !no_error)
{
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
if (!result && !no_error) if (!result && !no_error)
send_ok(thd); send_ok(thd);
/* Tables are automatically closed */ /* Tables are automatically closed */
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -3276,11 +3301,23 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, ...@@ -3276,11 +3301,23 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
} }
} }
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
if (!result)
{
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
close_thread_tables(thd); close_thread_tables(thd);
if (!result) if (!result)
send_ok(thd); send_ok(thd);
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -5241,6 +5278,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) ...@@ -5241,6 +5278,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
} }
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
close_thread_tables(thd); close_thread_tables(thd);
if (result) if (result)
...@@ -5297,6 +5341,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) ...@@ -5297,6 +5341,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
rebuild_check_host(); rebuild_check_host();
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
close_thread_tables(thd); close_thread_tables(thd);
if (result) if (result)
...@@ -5366,6 +5417,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) ...@@ -5366,6 +5417,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
rebuild_check_host(); rebuild_check_host();
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
close_thread_tables(thd); close_thread_tables(thd);
if (result) if (result)
...@@ -5541,6 +5599,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) ...@@ -5541,6 +5599,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} }
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
close_thread_tables(thd); close_thread_tables(thd);
......
...@@ -542,6 +542,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, ...@@ -542,6 +542,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
qinfo.db = db; qinfo.db = db;
qinfo.db_len = strlen(db); qinfo.db_len = strlen(db);
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
send_ok(thd, result); send_ok(thd, result);
...@@ -613,6 +614,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) ...@@ -613,6 +614,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
qinfo.db_len = strlen(db); qinfo.db_len = strlen(db);
thd->clear_error(); thd->clear_error();
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
send_ok(thd, result); send_ok(thd, result);
...@@ -736,6 +738,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -736,6 +738,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
qinfo.db_len = strlen(db); qinfo.db_len = strlen(db);
thd->clear_error(); thd->clear_error();
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
thd->server_status|= SERVER_STATUS_DB_DROPPED; thd->server_status|= SERVER_STATUS_DB_DROPPED;
...@@ -762,6 +765,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -762,6 +765,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
tbl_name_len= strlen(tbl->table_name) + 3; tbl_name_len= strlen(tbl->table_name) + 3;
if (query_pos + tbl_name_len + 1 >= query_end) if (query_pos + tbl_name_len + 1 >= query_end)
{ {
/* These DDL methods and logging protected with LOCK_mysql_create_db */
write_to_binlog(thd, query, query_pos -1 - query, db, db_len); write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
query_pos= query_data_start; query_pos= query_data_start;
} }
...@@ -774,6 +778,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -774,6 +778,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (query_pos != query_data_start) if (query_pos != query_data_start)
{ {
/* These DDL methods and logging protected with LOCK_mysql_create_db */
write_to_binlog(thd, query, query_pos -1 - query, db, db_len); write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
} }
} }
......
...@@ -3195,6 +3195,7 @@ mysql_execute_command(THD *thd) ...@@ -3195,6 +3195,7 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */ /* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog) if (!res && !lex->no_write_to_binlog)
{ {
/* Presumably, REPAIR and binlog writing doesn't require synchronization */
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); // No binlog error generated thd->clear_error(); // No binlog error generated
...@@ -3229,6 +3230,7 @@ mysql_execute_command(THD *thd) ...@@ -3229,6 +3230,7 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */ /* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog) if (!res && !lex->no_write_to_binlog)
{ {
/* Presumably, ANALYZE and binlog writing doesn't require synchronization */
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); // No binlog error generated thd->clear_error(); // No binlog error generated
...@@ -3254,6 +3256,7 @@ mysql_execute_command(THD *thd) ...@@ -3254,6 +3256,7 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */ /* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog) if (!res && !lex->no_write_to_binlog)
{ {
/* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); // No binlog error generated thd->clear_error(); // No binlog error generated
...@@ -3542,6 +3545,7 @@ mysql_execute_command(THD *thd) ...@@ -3542,6 +3545,7 @@ mysql_execute_command(THD *thd)
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
} }
/* DDL and binlog write order protected by LOCK_open */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists, res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary); lex->drop_temporary);
} }
...@@ -3830,15 +3834,9 @@ mysql_execute_command(THD *thd) ...@@ -3830,15 +3834,9 @@ mysql_execute_command(THD *thd)
break; break;
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list))) if (!(res= mysql_create_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
}
break; break;
} }
case SQLCOM_DROP_USER: case SQLCOM_DROP_USER:
...@@ -3848,15 +3846,9 @@ mysql_execute_command(THD *thd) ...@@ -3848,15 +3846,9 @@ mysql_execute_command(THD *thd)
break; break;
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list))) if (!(res= mysql_drop_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
}
break; break;
} }
case SQLCOM_RENAME_USER: case SQLCOM_RENAME_USER:
...@@ -3866,15 +3858,9 @@ mysql_execute_command(THD *thd) ...@@ -3866,15 +3858,9 @@ mysql_execute_command(THD *thd)
break; break;
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_rename_user(thd, lex->users_list))) if (!(res= mysql_rename_user(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
}
break; break;
} }
case SQLCOM_REVOKE_ALL: case SQLCOM_REVOKE_ALL:
...@@ -3882,15 +3868,9 @@ mysql_execute_command(THD *thd) ...@@ -3882,15 +3868,9 @@ mysql_execute_command(THD *thd)
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL)) check_global_access(thd,CREATE_USER_ACL))
break; break;
/* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list))) if (!(res = mysql_revoke_all(thd, lex->users_list)))
{
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
}
break; break;
} }
case SQLCOM_REVOKE: case SQLCOM_REVOKE:
...@@ -3949,6 +3929,7 @@ mysql_execute_command(THD *thd) ...@@ -3949,6 +3929,7 @@ mysql_execute_command(THD *thd)
check_grant_routine(thd, grants | GRANT_ACL, all_tables, check_grant_routine(thd, grants | GRANT_ACL, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, 0)) lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error; goto error;
/* Conditionally writes to binlog */
res= mysql_routine_grant(thd, all_tables, res= mysql_routine_grant(thd, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, lex->type == TYPE_ENUM_PROCEDURE,
lex->users_list, grants, lex->users_list, grants,
...@@ -3961,16 +3942,11 @@ mysql_execute_command(THD *thd) ...@@ -3961,16 +3942,11 @@ mysql_execute_command(THD *thd)
GRANT_ACL), GRANT_ACL),
all_tables, 0, UINT_MAX, 0)) all_tables, 0, UINT_MAX, 0))
goto error; goto error;
/* Conditionally writes to binlog */
res= mysql_table_grant(thd, all_tables, lex->users_list, res= mysql_table_grant(thd, all_tables, lex->users_list,
lex->columns, lex->grant, lex->columns, lex->grant,
lex->sql_command == SQLCOM_REVOKE); lex->sql_command == SQLCOM_REVOKE);
} }
if (!res && mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
} }
else else
{ {
...@@ -3981,16 +3957,11 @@ mysql_execute_command(THD *thd) ...@@ -3981,16 +3957,11 @@ mysql_execute_command(THD *thd)
goto error; goto error;
} }
else else
/* Conditionally writes to binlog */
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
lex->sql_command == SQLCOM_REVOKE); lex->sql_command == SQLCOM_REVOKE);
if (!res) if (!res)
{ {
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
if (lex->sql_command == SQLCOM_GRANT) if (lex->sql_command == SQLCOM_GRANT)
{ {
List_iterator <LEX_USER> str_list(lex->users_list); List_iterator <LEX_USER> str_list(lex->users_list);
...@@ -4028,6 +3999,7 @@ mysql_execute_command(THD *thd) ...@@ -4028,6 +3999,7 @@ mysql_execute_command(THD *thd)
We WANT to write and we CAN write. We WANT to write and we CAN write.
! we write after unlocking the table. ! we write after unlocking the table.
*/ */
/* Presumably, RESET and binlog writing doesn't require synchronization */
if (!lex->no_write_to_binlog && write_to_binlog) if (!lex->no_write_to_binlog && write_to_binlog)
{ {
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
...@@ -4564,20 +4536,16 @@ mysql_execute_command(THD *thd) ...@@ -4564,20 +4536,16 @@ mysql_execute_command(THD *thd)
already puts on CREATE FUNCTION. already puts on CREATE FUNCTION.
*/ */
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
/* Conditionally writes to binlog */
result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics); result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
else else
/* Conditionally writes to binlog */
result= sp_update_function(thd, lex->spname, &lex->sp_chistics); result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
} }
} }
switch (result) switch (result)
{ {
case SP_OK: case SP_OK:
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
break; break;
case SP_KEY_NOT_FOUND: case SP_KEY_NOT_FOUND:
...@@ -4622,9 +4590,11 @@ mysql_execute_command(THD *thd) ...@@ -4622,9 +4590,11 @@ mysql_execute_command(THD *thd)
} }
#endif #endif
if (lex->sql_command == SQLCOM_DROP_PROCEDURE) if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
else else
result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
} }
else else
{ {
...@@ -4637,6 +4607,8 @@ mysql_execute_command(THD *thd) ...@@ -4637,6 +4607,8 @@ mysql_execute_command(THD *thd)
{ {
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0)) if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
goto error; goto error;
/* Does NOT write to binlog */
if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
{ {
send_ok(thd); send_ok(thd);
...@@ -4657,12 +4629,6 @@ mysql_execute_command(THD *thd) ...@@ -4657,12 +4629,6 @@ mysql_execute_command(THD *thd)
switch (result) switch (result)
{ {
case SP_OK: case SP_OK:
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); send_ok(thd);
break; break;
case SP_KEY_NOT_FOUND: case SP_KEY_NOT_FOUND:
...@@ -4758,37 +4724,8 @@ mysql_execute_command(THD *thd) ...@@ -4758,37 +4724,8 @@ mysql_execute_command(THD *thd)
{ {
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog. */
if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) && res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
mysql_bin_log.is_open())
{
String buff;
const LEX_STRING command[3]=
{{(char *)STRING_WITH_LEN("CREATE ")},
{(char *)STRING_WITH_LEN("ALTER ")},
{(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
thd->clear_error();
buff.append(command[thd->lex->create_view_mode].str,
command[thd->lex->create_view_mode].length);
view_store_options(thd, first_table, &buff);
buff.append(STRING_WITH_LEN("VIEW "));
/* Test if user supplied a db (ie: we did not use thd->db) */
if (first_table->db && first_table->db[0] &&
(thd->db == NULL || strcmp(first_table->db, thd->db)))
{
append_identifier(thd, &buff, first_table->db,
first_table->db_length);
buff.append('.');
}
append_identifier(thd, &buff, first_table->table_name,
first_table->table_name_length);
buff.append(STRING_WITH_LEN(" AS "));
buff.append(first_table->source.str, first_table->source.length);
Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
mysql_bin_log.write(&qinfo);
}
break; break;
} }
case SQLCOM_DROP_VIEW: case SQLCOM_DROP_VIEW:
...@@ -4796,13 +4733,8 @@ mysql_execute_command(THD *thd) ...@@ -4796,13 +4733,8 @@ mysql_execute_command(THD *thd)
if (check_table_access(thd, DROP_ACL, all_tables, 0) || if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
end_active_trans(thd)) end_active_trans(thd))
goto error; goto error;
if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) && /* Conditionally writes to binlog. */
mysql_bin_log.is_open()) res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
break; break;
} }
case SQLCOM_CREATE_TRIGGER: case SQLCOM_CREATE_TRIGGER:
...@@ -4810,6 +4742,7 @@ mysql_execute_command(THD *thd) ...@@ -4810,6 +4742,7 @@ mysql_execute_command(THD *thd)
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 1); res= mysql_create_or_drop_trigger(thd, all_tables, 1);
/* We don't care about trigger body after this point */ /* We don't care about trigger body after this point */
...@@ -4822,6 +4755,7 @@ mysql_execute_command(THD *thd) ...@@ -4822,6 +4755,7 @@ mysql_execute_command(THD *thd)
if (end_active_trans(thd)) if (end_active_trans(thd))
goto error; goto error;
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 0); res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break; break;
} }
......
...@@ -3168,6 +3168,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3168,6 +3168,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
if (alter_info->tablespace_op != NO_TABLESPACE_OP) if (alter_info->tablespace_op != NO_TABLESPACE_OP)
/* Conditionally writes to binlog. */
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
alter_info->tablespace_op)); alter_info->tablespace_op));
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
...@@ -3249,10 +3250,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3249,10 +3250,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
!table->s->tmp_table) // no need to touch frm !table->s->tmp_table) // no need to touch frm
{ {
error=0; error=0;
VOID(pthread_mutex_lock(&LOCK_open));
if (new_name != table_name || new_db != db) if (new_name != table_name || new_db != db)
{ {
thd->proc_info="rename"; thd->proc_info="rename";
VOID(pthread_mutex_lock(&LOCK_open));
/* Then do a 'simple' rename of the table */ /* Then do a 'simple' rename of the table */
error=0; error=0;
if (!access(new_name_buff,F_OK)) if (!access(new_name_buff,F_OK))
...@@ -3274,7 +3275,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3274,7 +3275,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error= -1; error= -1;
} }
} }
VOID(pthread_mutex_unlock(&LOCK_open));
} }
if (!error) if (!error)
...@@ -3283,16 +3283,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3283,16 +3283,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
case LEAVE_AS_IS: case LEAVE_AS_IS:
break; break;
case ENABLE: case ENABLE:
VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
VOID(pthread_mutex_unlock(&LOCK_open));
error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
/* COND_refresh will be signaled in close_thread_tables() */ /* COND_refresh will be signaled in close_thread_tables() */
break; break;
case DISABLE: case DISABLE:
VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
VOID(pthread_mutex_unlock(&LOCK_open));
error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
/* COND_refresh will be signaled in close_thread_tables() */ /* COND_refresh will be signaled in close_thread_tables() */
break; break;
...@@ -3322,6 +3318,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3322,6 +3318,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
error= -1; error= -1;
} }
VOID(pthread_mutex_unlock(&LOCK_open));
table_list->table=0; // For query cache table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0); query_cache_invalidate3(thd, table_list, 0);
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -3768,6 +3765,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3768,6 +3765,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
my_free((gptr) new_table,MYF(0)); my_free((gptr) new_table,MYF(0));
goto err; goto err;
} }
/*
Writing to the binlog does not need to be synchronized for temporary tables,
which are thread-specific.
*/
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); thd->clear_error();
...@@ -3950,7 +3951,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -3950,7 +3951,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->some_tables_deleted=0; thd->some_tables_deleted=0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
err: err:
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
......
...@@ -268,8 +268,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) ...@@ -268,8 +268,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
table->triggers->drop_trigger(thd, tables)); table->triggers->drop_trigger(thd, tables));
end: end:
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
if (!result) if (!result)
{ {
...@@ -302,9 +300,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) ...@@ -302,9 +300,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE); Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE);
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
}
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
if (!result)
send_ok(thd); send_ok(thd);
}
DBUG_RETURN(result); DBUG_RETURN(result);
} }
......
...@@ -162,6 +162,7 @@ bool check_duplicate_names(List<Item> &item_list, bool gen_unique_view_name) ...@@ -162,6 +162,7 @@ bool check_duplicate_names(List<Item> &item_list, bool gen_unique_view_name)
SYNOPSIS SYNOPSIS
mysql_create_view() mysql_create_view()
thd - thread handler thd - thread handler
views - views to create
mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
RETURN VALUE RETURN VALUE
...@@ -169,7 +170,7 @@ bool check_duplicate_names(List<Item> &item_list, bool gen_unique_view_name) ...@@ -169,7 +170,7 @@ bool check_duplicate_names(List<Item> &item_list, bool gen_unique_view_name)
TRUE Error TRUE Error
*/ */
bool mysql_create_view(THD *thd, bool mysql_create_view(THD *thd, TABLE_LIST *views,
enum_view_create_mode mode) enum_view_create_mode mode)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
...@@ -490,6 +491,37 @@ bool mysql_create_view(THD *thd, ...@@ -490,6 +491,37 @@ bool mysql_create_view(THD *thd,
} }
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
res= mysql_register_view(thd, view, mode); res= mysql_register_view(thd, view, mode);
if (mysql_bin_log.is_open())
{
String buff;
const LEX_STRING command[3]=
{{(char *)STRING_WITH_LEN("CREATE ")},
{(char *)STRING_WITH_LEN("ALTER ")},
{(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
buff.append(command[thd->lex->create_view_mode].str,
command[thd->lex->create_view_mode].length);
view_store_options(thd, views, &buff);
buff.append(STRING_WITH_LEN("VIEW "));
/* Test if user supplied a db (ie: we did not use thd->db) */
if (views->db && views->db[0] &&
(thd->db == NULL || strcmp(views->db, thd->db)))
{
append_identifier(thd, &buff, views->db,
views->db_length);
buff.append('.');
}
append_identifier(thd, &buff, views->table_name,
views->table_name_length);
buff.append(STRING_WITH_LEN(" AS "));
buff.append(views->source.str, views->source.length);
Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
if (view->revision != 1) if (view->revision != 1)
query_cache_invalidate3(thd, view, 0); query_cache_invalidate3(thd, view, 0);
...@@ -1229,12 +1261,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1229,12 +1261,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
bool type= 0; bool type= 0;
db_type not_used; db_type not_used;
VOID(pthread_mutex_lock(&LOCK_open));
for (view= views; view; view= view->next_local) for (view= views; view; view= view->next_local)
{ {
strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/", strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
view->table_name, reg_ext, NullS); view->table_name, reg_ext, NullS);
(void) unpack_filename(path, path); (void) unpack_filename(path, path);
VOID(pthread_mutex_lock(&LOCK_open));
if (access(path, F_OK) || if (access(path, F_OK) ||
(type= (mysql_frm_type(thd, path, &not_used) != FRMTYPE_VIEW))) (type= (mysql_frm_type(thd, path, &not_used) != FRMTYPE_VIEW)))
{ {
...@@ -1245,7 +1277,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1245,7 +1277,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
name); name);
VOID(pthread_mutex_unlock(&LOCK_open));
continue; continue;
} }
if (type) if (type)
...@@ -1258,8 +1289,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1258,8 +1289,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
goto err; goto err;
query_cache_invalidate3(thd, view, 0); query_cache_invalidate3(thd, view, 0);
sp_cache_invalidate(); sp_cache_invalidate();
VOID(pthread_mutex_unlock(&LOCK_open));
} }
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_mutex_unlock(&LOCK_open));
send_ok(thd); send_ok(thd);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
bool mysql_create_view(THD *thd, bool mysql_create_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode); enum_view_create_mode mode);
bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table); bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment