mirror of
https://github.com/MariaDB/server.git
synced 2025-08-31 22:22:30 +03:00
merge of mysql-5.5 into mysql-5.5-wl1054
This commit is contained in:
626
sql/sql_parse.cc
626
sql/sql_parse.cc
@@ -50,6 +50,8 @@
|
||||
// mysql_backup_table,
|
||||
// mysql_restore_table
|
||||
#include "sql_truncate.h" // mysql_truncate_table
|
||||
#include "sql_reload.h" // reload_acl_and_cache
|
||||
#include "sql_admin.h" // mysql_assign_to_keycache
|
||||
#include "sql_connect.h" // check_user,
|
||||
// decrease_user_connections,
|
||||
// thd_init_client_charset, check_mqh,
|
||||
@@ -658,8 +660,7 @@ end:
|
||||
every child. Set 'db' for every child if not present.
|
||||
*/
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
static bool check_merge_table_access(THD *thd, char *db,
|
||||
TABLE_LIST *table_list)
|
||||
bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list)
|
||||
{
|
||||
int error= 0;
|
||||
|
||||
@@ -1626,140 +1627,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
|
||||
|
||||
In brief: take exclusive locks, expel tables from the table
|
||||
cache, reopen the tables, enter the 'LOCKED TABLES' mode,
|
||||
downgrade the locks.
|
||||
Note: the function is written to be called from
|
||||
mysql_execute_command(), it is not reusable in arbitrary
|
||||
execution context.
|
||||
|
||||
Required privileges
|
||||
-------------------
|
||||
Since the statement implicitly enters LOCK TABLES mode,
|
||||
it requires LOCK TABLES privilege on every table.
|
||||
But since the rest of FLUSH commands require
|
||||
the global RELOAD_ACL, it also requires RELOAD_ACL.
|
||||
|
||||
Compatibility with the global read lock
|
||||
---------------------------------------
|
||||
We don't wait for the GRL, since neither the
|
||||
5.1 combination that this new statement is intended to
|
||||
replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
|
||||
nor FLUSH TABLES WITH READ LOCK do.
|
||||
@todo: this is not implemented, Dmitry disagrees.
|
||||
Currently we wait for GRL in another connection,
|
||||
but are compatible with a GRL in our own connection.
|
||||
|
||||
Behaviour under LOCK TABLES
|
||||
---------------------------
|
||||
Bail out: i.e. don't perform an implicit UNLOCK TABLES.
|
||||
This is not consistent with LOCK TABLES statement, but is
|
||||
in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
|
||||
try to not introduce any new statements with implicit
|
||||
semantics.
|
||||
|
||||
Compatibility with parallel updates
|
||||
-----------------------------------
|
||||
As a result, we will wait for all open transactions
|
||||
against the tables to complete. After the lock downgrade,
|
||||
new transactions will be able to read the tables, but not
|
||||
write to them.
|
||||
|
||||
Differences from FLUSH TABLES <list>
|
||||
-------------------------------------
|
||||
- you can't flush WITH READ LOCK a non-existent table
|
||||
- you can't flush WITH READ LOCK under LOCK TABLES
|
||||
- currently incompatible with the GRL (@todo: fix)
|
||||
|
||||
Effect on views and temporary tables.
|
||||
------------------------------------
|
||||
You can only apply this command to existing base tables.
|
||||
If a view with such name exists, ER_WRONG_OBJECT is returned.
|
||||
If a temporary table with such name exists, it's ignored:
|
||||
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
|
||||
is returned.
|
||||
*/
|
||||
|
||||
static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
||||
{
|
||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
||||
TABLE_LIST *table_list;
|
||||
|
||||
/*
|
||||
This is called from SQLCOM_FLUSH, the transaction has
|
||||
been committed implicitly.
|
||||
*/
|
||||
|
||||
/* RELOAD_ACL is checked by the caller. Check table-level privileges. */
|
||||
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error;
|
||||
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
@todo: Since lock_table_names() acquires a global IX
|
||||
lock, this actually waits for a GRL in another connection.
|
||||
We are thus introducing an incompatibility.
|
||||
Do nothing for now, since not taking a global IX violates
|
||||
current internal MDL asserts, fix after discussing with
|
||||
Dmitry.
|
||||
*/
|
||||
if (lock_table_names(thd, all_tables, 0, thd->variables.lock_wait_timeout,
|
||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
||||
goto error;
|
||||
|
||||
for (table_list= all_tables; table_list;
|
||||
table_list= table_list->next_global)
|
||||
{
|
||||
/* Remove the table from cache. */
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
|
||||
table_list->db,
|
||||
table_list->table_name);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
|
||||
/* Skip views and temporary tables. */
|
||||
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
|
||||
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
|
||||
}
|
||||
|
||||
if (open_and_lock_tables(thd, all_tables, FALSE,
|
||||
MYSQL_OPEN_HAS_MDL_LOCK,
|
||||
&lock_tables_prelocking_strategy) ||
|
||||
thd->locked_tables_list.init_locked_tables(thd))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
thd->variables.option_bits|= OPTION_TABLE_LOCK;
|
||||
|
||||
/*
|
||||
Downgrade the exclusive locks.
|
||||
Use MDL_SHARED_NO_WRITE as the intended
|
||||
post effect of this call is identical
|
||||
to LOCK TABLES <...> READ, and we didn't use
|
||||
thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES
|
||||
hacks to enter the LTM.
|
||||
@todo: release the global IX lock here!!!
|
||||
*/
|
||||
for (table_list= all_tables; table_list;
|
||||
table_list= table_list->next_global)
|
||||
table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE);
|
||||
|
||||
return FALSE;
|
||||
|
||||
error:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read query from packet and store in thd->query.
|
||||
Used in COM_QUERY and COM_STMT_PREPARE.
|
||||
@@ -2521,13 +2388,7 @@ case SQLCOM_PREPARE:
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set strategies: reset default or 'prepared' values. */
|
||||
create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
|
||||
create_table->lock_strategy= TABLE_LIST::OTLS_DOWNGRADE_IF_EXISTS;
|
||||
|
||||
/*
|
||||
Close any open handlers for the table
|
||||
*/
|
||||
/* Close any open handlers for the table. */
|
||||
mysql_ha_rm_tables(thd, create_table);
|
||||
|
||||
if (select_lex->item_list.elements) // With select
|
||||
@@ -2587,44 +2448,25 @@ case SQLCOM_PREPARE:
|
||||
goto end_with_restore_list;
|
||||
}
|
||||
|
||||
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
/* Base table and temporary table are not in the same name space. */
|
||||
create_table->open_type= OT_BASE_ONLY;
|
||||
}
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0)))
|
||||
{
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts
|
||||
of query
|
||||
*/
|
||||
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||
/* The table already exists */
|
||||
if (create_table->table)
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
|
||||
if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
{
|
||||
update_non_unique_table_error(create_table, "CREATE", duplicate);
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_TABLE_EXISTS_ERROR,
|
||||
ER(ER_TABLE_EXISTS_ERROR),
|
||||
create_info.alias);
|
||||
my_ok(thd);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias);
|
||||
res= 1;
|
||||
goto end_with_restore_list;
|
||||
}
|
||||
}
|
||||
/* If we create merge table, we have to test tables in merge, too */
|
||||
if (create_info.used_fields & HA_CREATE_USED_UNION)
|
||||
{
|
||||
TABLE_LIST *tab;
|
||||
for (tab= create_info.merge_list.first;
|
||||
tab;
|
||||
tab= tab->next_local)
|
||||
{
|
||||
TABLE_LIST *duplicate;
|
||||
if ((duplicate= unique_table(thd, tab, select_tables, 0)))
|
||||
{
|
||||
update_non_unique_table_error(tab, "CREATE", duplicate);
|
||||
res= 1;
|
||||
goto end_with_restore_list;
|
||||
}
|
||||
}
|
||||
goto end_with_restore_list;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2657,7 +2499,7 @@ case SQLCOM_PREPARE:
|
||||
res= handle_select(thd, lex, result, 0);
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
lex->link_first_table_back(create_table, link_to_local);
|
||||
}
|
||||
}
|
||||
@@ -2762,77 +2604,6 @@ end_with_restore_list:
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
||||
case SQLCOM_ALTER_TABLE:
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
{
|
||||
ulong priv=0;
|
||||
ulong priv_needed= ALTER_ACL;
|
||||
/*
|
||||
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
|
||||
so we have to use a copy of this structure to make execution
|
||||
prepared statement- safe. A shallow copy is enough as no memory
|
||||
referenced from this structure will be modified.
|
||||
*/
|
||||
HA_CREATE_INFO create_info(lex->create_info);
|
||||
Alter_info alter_info(lex->alter_info, thd->mem_root);
|
||||
|
||||
if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
|
||||
goto error;
|
||||
/*
|
||||
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
|
||||
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
|
||||
*/
|
||||
if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
|
||||
priv_needed|= DROP_ACL;
|
||||
|
||||
/* Must be set in the parser */
|
||||
DBUG_ASSERT(select_lex->db);
|
||||
if (check_access(thd, priv_needed, first_table->db,
|
||||
&first_table->grant.privilege,
|
||||
&first_table->grant.m_internal,
|
||||
0, 0) ||
|
||||
check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db,
|
||||
&priv,
|
||||
NULL, /* Do not use first_table->grant with select_lex->db */
|
||||
0, 0) ||
|
||||
check_merge_table_access(thd, first_table->db,
|
||||
create_info.merge_list.first))
|
||||
goto error; /* purecov: inspected */
|
||||
if (check_grant(thd, priv_needed, all_tables, FALSE, UINT_MAX, FALSE))
|
||||
goto error;
|
||||
if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
|
||||
{ // Rename of table
|
||||
TABLE_LIST tmp_table;
|
||||
bzero((char*) &tmp_table,sizeof(tmp_table));
|
||||
tmp_table.table_name= lex->name.str;
|
||||
tmp_table.db=select_lex->db;
|
||||
tmp_table.grant.privilege=priv;
|
||||
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE,
|
||||
UINT_MAX, FALSE))
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Don't yet allow changing of symlinks with ALTER TABLE */
|
||||
if (create_info.data_file_name)
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
|
||||
"DATA DIRECTORY");
|
||||
if (create_info.index_file_name)
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||
WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
|
||||
"INDEX DIRECTORY");
|
||||
create_info.data_file_name= create_info.index_file_name= NULL;
|
||||
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= mysql_alter_table(thd, select_lex->db, lex->name.str,
|
||||
&create_info,
|
||||
first_table,
|
||||
&alter_info,
|
||||
select_lex->order_list.elements,
|
||||
select_lex->order_list.first,
|
||||
lex->ignore);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_RENAME_TABLE:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
@@ -2952,81 +2723,6 @@ end_with_restore_list:
|
||||
res = mysql_checksum_table(thd, first_table, &lex->check_opt);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REPAIR:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= mysql_repair_table(thd, first_table, &lex->check_opt);
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/*
|
||||
Presumably, REPAIR and binlog writing doesn't require synchronization
|
||||
*/
|
||||
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
||||
}
|
||||
select_lex->table_list.first= first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_CHECK:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_table_access(thd, SELECT_ACL, all_tables,
|
||||
TRUE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res = mysql_check_table(thd, first_table, &lex->check_opt);
|
||||
select_lex->table_list.first= first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_ANALYZE:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= mysql_analyze_table(thd, first_table, &lex->check_opt);
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/*
|
||||
Presumably, ANALYZE and binlog writing doesn't require synchronization
|
||||
*/
|
||||
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
||||
}
|
||||
select_lex->table_list.first= first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLCOM_OPTIMIZE:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
|
||||
mysql_recreate_table(thd, first_table) :
|
||||
mysql_optimize_table(thd, first_table, &lex->check_opt);
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/*
|
||||
Presumably, OPTIMIZE and binlog writing doesn't require synchronization
|
||||
*/
|
||||
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
||||
}
|
||||
select_lex->table_list.first= first_table;
|
||||
lex->query_tables=all_tables;
|
||||
break;
|
||||
}
|
||||
case SQLCOM_UPDATE:
|
||||
{
|
||||
ha_rows found= 0, updated= 0;
|
||||
@@ -3247,23 +2943,6 @@ end_with_restore_list:
|
||||
|
||||
break;
|
||||
}
|
||||
case SQLCOM_TRUNCATE:
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (check_one_table_access(thd, DROP_ACL, all_tables))
|
||||
goto error;
|
||||
/*
|
||||
Don't allow this within a transaction because we want to use
|
||||
re-generate table
|
||||
*/
|
||||
if (thd->in_active_multi_stmt_transaction())
|
||||
{
|
||||
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
|
||||
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
|
||||
goto error;
|
||||
}
|
||||
if (! (res= mysql_truncate_table(thd, first_table)))
|
||||
my_ok(thd);
|
||||
break;
|
||||
case SQLCOM_DELETE:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
@@ -3345,7 +3024,7 @@ end_with_restore_list:
|
||||
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
thd->variables.option_bits|= OPTION_KEEP_LOG;
|
||||
}
|
||||
/* DDL and binlog write order protected by LOCK_open */
|
||||
/* DDL and binlog write order are protected by metadata locks. */
|
||||
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
|
||||
lex->drop_temporary);
|
||||
}
|
||||
@@ -3898,6 +3577,10 @@ end_with_restore_list:
|
||||
|
||||
if (first_table && lex->type & REFRESH_READ_LOCK)
|
||||
{
|
||||
/* Check table-level privileges. */
|
||||
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
|
||||
FALSE, UINT_MAX, FALSE))
|
||||
goto error;
|
||||
if (flush_tables_with_read_lock(thd, all_tables))
|
||||
goto error;
|
||||
my_ok(thd);
|
||||
@@ -4657,6 +4340,14 @@ create_sp_error:
|
||||
my_ok(thd, 1);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_ANALYZE:
|
||||
case SQLCOM_CHECK:
|
||||
case SQLCOM_OPTIMIZE:
|
||||
case SQLCOM_REPAIR:
|
||||
case SQLCOM_TRUNCATE:
|
||||
case SQLCOM_ALTER_TABLE:
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
/* fall through */
|
||||
case SQLCOM_SIGNAL:
|
||||
case SQLCOM_RESIGNAL:
|
||||
DBUG_ASSERT(lex->m_stmt != NULL);
|
||||
@@ -6637,258 +6328,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reload/resets privileges and the different caches.
|
||||
|
||||
@param thd Thread handler (can be NULL!)
|
||||
@param options What should be reset/reloaded (tables, privileges, slave...)
|
||||
@param tables Tables to flush (if any)
|
||||
@param write_to_binlog True if we can write to the binlog.
|
||||
|
||||
@note Depending on 'options', it may be very bad to write the
|
||||
query to the binlog (e.g. FLUSH SLAVE); this is a
|
||||
pointer where reload_acl_and_cache() will put 0 if
|
||||
it thinks we really should not write to the binlog.
|
||||
Otherwise it will put 1.
|
||||
|
||||
@return Error status code
|
||||
@retval 0 Ok
|
||||
@retval !=0 Error; thd->killed is set or thd->is_error() is true
|
||||
*/
|
||||
|
||||
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
|
||||
bool *write_to_binlog)
|
||||
{
|
||||
bool result=0;
|
||||
select_errors=0; /* Write if more errors */
|
||||
bool tmp_write_to_binlog= 1;
|
||||
|
||||
DBUG_ASSERT(!thd || !thd->in_sub_stmt);
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (options & REFRESH_GRANT)
|
||||
{
|
||||
THD *tmp_thd= 0;
|
||||
/*
|
||||
If reload_acl_and_cache() is called from SIGHUP handler we have to
|
||||
allocate temporary THD for execution of acl_reload()/grant_reload().
|
||||
*/
|
||||
if (!thd && (thd= (tmp_thd= new THD)))
|
||||
{
|
||||
thd->thread_stack= (char*) &tmp_thd;
|
||||
thd->store_globals();
|
||||
}
|
||||
|
||||
if (thd)
|
||||
{
|
||||
bool reload_acl_failed= acl_reload(thd);
|
||||
bool reload_grants_failed= grant_reload(thd);
|
||||
bool reload_servers_failed= servers_reload(thd);
|
||||
|
||||
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
|
||||
{
|
||||
result= 1;
|
||||
/*
|
||||
When an error is returned, my_message may have not been called and
|
||||
the client will hang waiting for a response.
|
||||
*/
|
||||
my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_thd)
|
||||
{
|
||||
delete tmp_thd;
|
||||
/* Remember that we don't have a THD */
|
||||
my_pthread_setspecific_ptr(THR_THD, 0);
|
||||
thd= 0;
|
||||
}
|
||||
reset_mqh((LEX_USER *)NULL, TRUE);
|
||||
}
|
||||
#endif
|
||||
if (options & REFRESH_LOG)
|
||||
{
|
||||
/*
|
||||
Flush the normal query log, the update log, the binary log,
|
||||
the slow query log, the relay log (if it exists) and the log
|
||||
tables.
|
||||
*/
|
||||
|
||||
options|= REFRESH_BINARY_LOG;
|
||||
options|= REFRESH_RELAY_LOG;
|
||||
options|= REFRESH_SLOW_LOG;
|
||||
options|= REFRESH_GENERAL_LOG;
|
||||
options|= REFRESH_ENGINE_LOG;
|
||||
options|= REFRESH_ERROR_LOG;
|
||||
}
|
||||
|
||||
if (options & REFRESH_ERROR_LOG)
|
||||
if (flush_error_log())
|
||||
result= 1;
|
||||
|
||||
if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
|
||||
logger.flush_slow_log();
|
||||
|
||||
if ((options & REFRESH_GENERAL_LOG) && opt_log)
|
||||
logger.flush_general_log();
|
||||
|
||||
if (options & REFRESH_ENGINE_LOG)
|
||||
if (ha_flush_logs(NULL))
|
||||
result= 1;
|
||||
|
||||
if (options & REFRESH_BINARY_LOG)
|
||||
{
|
||||
/*
|
||||
Writing this command to the binlog may result in infinite loops
|
||||
when doing mysqlbinlog|mysql, and anyway it does not really make
|
||||
sense to log it automatically (would cause more trouble to users
|
||||
than it would help them)
|
||||
*/
|
||||
tmp_write_to_binlog= 0;
|
||||
if (mysql_bin_log.is_open())
|
||||
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
|
||||
}
|
||||
if (options & REFRESH_RELAY_LOG)
|
||||
{
|
||||
#ifdef HAVE_REPLICATION
|
||||
mysql_mutex_lock(&LOCK_active_mi);
|
||||
rotate_relay_log(active_mi);
|
||||
mysql_mutex_unlock(&LOCK_active_mi);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
if (options & REFRESH_QUERY_CACHE_FREE)
|
||||
{
|
||||
query_cache.pack(); // FLUSH QUERY CACHE
|
||||
options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
|
||||
}
|
||||
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
|
||||
{
|
||||
query_cache.flush(); // RESET QUERY CACHE
|
||||
}
|
||||
#endif /*HAVE_QUERY_CACHE*/
|
||||
|
||||
DBUG_ASSERT(!thd || thd->locked_tables_mode ||
|
||||
!thd->mdl_context.has_locks() ||
|
||||
thd->handler_tables_hash.records ||
|
||||
thd->global_read_lock.is_acquired());
|
||||
|
||||
/*
|
||||
Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
|
||||
(see sql_yacc.yy)
|
||||
*/
|
||||
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
|
||||
{
|
||||
if ((options & REFRESH_READ_LOCK) && thd)
|
||||
{
|
||||
/*
|
||||
On the first hand we need write lock on the tables to be flushed,
|
||||
on the other hand we must not try to aspire a global read lock
|
||||
if we have a write locked table as this would lead to a deadlock
|
||||
when trying to reopen (and re-lock) the table after the flush.
|
||||
*/
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
Writing to the binlog could cause deadlocks, as we don't log
|
||||
UNLOCK TABLES
|
||||
*/
|
||||
tmp_write_to_binlog= 0;
|
||||
if (thd->global_read_lock.lock_global_read_lock(thd))
|
||||
return 1; // Killed
|
||||
if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
|
||||
FALSE : TRUE))
|
||||
result= 1;
|
||||
|
||||
if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
|
||||
{
|
||||
/* Don't leave things in a half-locked state */
|
||||
thd->global_read_lock.unlock_global_read_lock(thd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thd && thd->locked_tables_mode)
|
||||
{
|
||||
/*
|
||||
If we are under LOCK TABLES we should have a write
|
||||
lock on tables which we are going to flush.
|
||||
*/
|
||||
if (tables)
|
||||
{
|
||||
for (TABLE_LIST *t= tables; t; t= t->next_local)
|
||||
if (!find_table_for_mdl_upgrade(thd->open_tables, t->db,
|
||||
t->table_name, FALSE))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
|
||||
{
|
||||
if (! tab->mdl_ticket->is_upgradable_or_exclusive())
|
||||
{
|
||||
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
|
||||
tab->s->table_name.str);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ?
|
||||
FALSE : TRUE))
|
||||
result= 1;
|
||||
}
|
||||
my_dbopt_cleanup();
|
||||
}
|
||||
if (options & REFRESH_HOSTS)
|
||||
hostname_cache_refresh();
|
||||
if (thd && (options & REFRESH_STATUS))
|
||||
refresh_status(thd);
|
||||
if (options & REFRESH_THREADS)
|
||||
flush_thread_cache();
|
||||
#ifdef HAVE_REPLICATION
|
||||
if (options & REFRESH_MASTER)
|
||||
{
|
||||
DBUG_ASSERT(thd);
|
||||
tmp_write_to_binlog= 0;
|
||||
if (reset_master(thd))
|
||||
{
|
||||
result=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef OPENSSL
|
||||
if (options & REFRESH_DES_KEY_FILE)
|
||||
{
|
||||
if (des_key_file && load_des_key_file(des_key_file))
|
||||
result= 1;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_REPLICATION
|
||||
if (options & REFRESH_SLAVE)
|
||||
{
|
||||
tmp_write_to_binlog= 0;
|
||||
mysql_mutex_lock(&LOCK_active_mi);
|
||||
if (reset_slave(thd, active_mi))
|
||||
result=1;
|
||||
mysql_mutex_unlock(&LOCK_active_mi);
|
||||
}
|
||||
#endif
|
||||
if (options & REFRESH_USER_RESOURCES)
|
||||
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
|
||||
*write_to_binlog= tmp_write_to_binlog;
|
||||
/*
|
||||
If the query was killed then this function must fail.
|
||||
*/
|
||||
return result || (thd ? thd->killed : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
kill on thread.
|
||||
|
||||
@@ -7420,7 +6859,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex)
|
||||
|
||||
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
|
||||
create_table->open_type= OT_TEMPORARY_ONLY;
|
||||
else if (!lex->select_lex.item_list.elements)
|
||||
else
|
||||
create_table->open_type= OT_BASE_ONLY;
|
||||
|
||||
if (!lex->select_lex.item_list.elements)
|
||||
@@ -7800,6 +7239,7 @@ bool parse_sql(THD *thd,
|
||||
{
|
||||
bool ret_value;
|
||||
DBUG_ASSERT(thd->m_parser_state == NULL);
|
||||
DBUG_ASSERT(thd->lex->m_stmt == NULL);
|
||||
|
||||
MYSQL_QUERY_PARSE_START(thd->query());
|
||||
/* Backup creation context. */
|
||||
|
Reference in New Issue
Block a user