merge of 2876.430.11 & 2876.430.1
CF_PREOPEN_TMP_TABLES & CF_HA_CLOSE & Patch for Bug#11746602 (27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations).
This commit is contained in:
parent
94d722b6a4
commit
70092601bc
@ -4643,6 +4643,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
|||||||
Note that during creation of temporary table we still need to check
|
Note that during creation of temporary table we still need to check
|
||||||
if user has CREATE_TMP_ACL.
|
if user has CREATE_TMP_ACL.
|
||||||
*/
|
*/
|
||||||
|
tl->grant.privilege|= TMP_TABLE_ACLS;
|
||||||
tl->grant.want_privilege= 0;
|
tl->grant.want_privilege= 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||||||
MDL_EXCLUSIVE, MDL_TRANSACTION);
|
MDL_EXCLUSIVE, MDL_TRANSACTION);
|
||||||
|
|
||||||
if (lock_table_names(thd, table_list, table_list->next_global,
|
if (lock_table_names(thd, table_list, table_list->next_global,
|
||||||
thd->variables.lock_wait_timeout,
|
thd->variables.lock_wait_timeout, 0))
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
has_mdl_lock= TRUE;
|
has_mdl_lock= TRUE;
|
||||||
|
|
||||||
|
@ -2276,14 +2276,15 @@ TABLE *find_temporary_table(THD *thd,
|
|||||||
|
|
||||||
int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
|
int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
|
||||||
{
|
{
|
||||||
TABLE *table;
|
|
||||||
DBUG_ENTER("drop_temporary_table");
|
DBUG_ENTER("drop_temporary_table");
|
||||||
DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
|
DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
|
||||||
table_list->db, table_list->table_name));
|
table_list->db, table_list->table_name));
|
||||||
|
|
||||||
if (!(table= find_temporary_table(thd, table_list)))
|
if (!is_temporary_table(table_list))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
TABLE *table= table_list->table;
|
||||||
|
|
||||||
/* Table might be in use by some outer statement. */
|
/* Table might be in use by some outer statement. */
|
||||||
if (table->query_id && table->query_id != thd->query_id)
|
if (table->query_id && table->query_id != thd->query_id)
|
||||||
{
|
{
|
||||||
@ -2291,7 +2292,6 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
|
|||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_trans != NULL)
|
|
||||||
*is_trans= table->file->has_transactions();
|
*is_trans= table->file->has_transactions();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2300,6 +2300,7 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
|
|||||||
*/
|
*/
|
||||||
mysql_lock_remove(thd, thd->lock, table);
|
mysql_lock_remove(thd, thd->lock, table);
|
||||||
close_temporary_table(thd, table, 1, 1);
|
close_temporary_table(thd, table, 1, 1);
|
||||||
|
table_list->table= NULL;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4238,8 +4239,7 @@ recover_from_failed_open(THD *thd)
|
|||||||
case OT_DISCOVER:
|
case OT_DISCOVER:
|
||||||
{
|
{
|
||||||
if ((result= lock_table_names(thd, m_failed_table, NULL,
|
if ((result= lock_table_names(thd, m_failed_table, NULL,
|
||||||
get_timeout(),
|
get_timeout(), 0)))
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY)))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
|
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
|
||||||
@ -4255,8 +4255,7 @@ recover_from_failed_open(THD *thd)
|
|||||||
case OT_REPAIR:
|
case OT_REPAIR:
|
||||||
{
|
{
|
||||||
if ((result= lock_table_names(thd, m_failed_table, NULL,
|
if ((result= lock_table_names(thd, m_failed_table, NULL,
|
||||||
get_timeout(),
|
get_timeout(), 0)))
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY)))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
|
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
|
||||||
|
@ -93,7 +93,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
|||||||
/* mysql_lock_tables() and open_table() flags bits */
|
/* mysql_lock_tables() and open_table() flags bits */
|
||||||
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
|
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
|
||||||
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
|
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
|
||||||
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
|
/* MYSQL_OPEN_TEMPORARY_ONLY (0x0004) is not used anymore. */
|
||||||
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
|
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
|
||||||
#define MYSQL_LOCK_LOG_TABLE 0x0010
|
#define MYSQL_LOCK_LOG_TABLE 0x0010
|
||||||
/**
|
/**
|
||||||
@ -106,8 +106,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
|||||||
a new instance of the table.
|
a new instance of the table.
|
||||||
*/
|
*/
|
||||||
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
|
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
|
||||||
/** Don't look up the table in the list of temporary tables. */
|
/* 0x0080 used to be MYSQL_OPEN_SKIP_TEMPORARY */
|
||||||
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
|
|
||||||
/** Fail instead of waiting when conficting metadata lock is discovered. */
|
/** Fail instead of waiting when conficting metadata lock is discovered. */
|
||||||
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
|
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
|
||||||
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
|
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
|
||||||
@ -140,7 +139,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
|||||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
|
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
|
||||||
MYSQL_LOCK_IGNORE_TIMEOUT |\
|
MYSQL_LOCK_IGNORE_TIMEOUT |\
|
||||||
MYSQL_OPEN_GET_NEW_TABLE |\
|
MYSQL_OPEN_GET_NEW_TABLE |\
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY |\
|
|
||||||
MYSQL_OPEN_HAS_MDL_LOCK)
|
MYSQL_OPEN_HAS_MDL_LOCK)
|
||||||
|
|
||||||
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||||
|
@ -815,7 +815,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
|||||||
|
|
||||||
/* Lock all tables and stored routines about to be dropped. */
|
/* Lock all tables and stored routines about to be dropped. */
|
||||||
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
|
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY) ||
|
0) ||
|
||||||
lock_db_routines(thd, db))
|
lock_db_routines(thd, db))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
@ -3918,10 +3918,10 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This shouldn't happen as creation of temporary table should make
|
This shouldn't happen as creation of temporary table should make
|
||||||
it preparable for open. But let us do close_temporary_table() here
|
it preparable for open. Anyway we can't drop temporary table if
|
||||||
just in case.
|
we are unable to find it.
|
||||||
*/
|
*/
|
||||||
drop_temporary_table(thd, create_table, NULL);
|
DBUG_ASSERT(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
table= create_table->table;
|
table= create_table->table;
|
||||||
|
116
sql/sql_parse.cc
116
sql/sql_parse.cc
@ -24,7 +24,7 @@
|
|||||||
// set_handler_table_locks,
|
// set_handler_table_locks,
|
||||||
// lock_global_read_lock,
|
// lock_global_read_lock,
|
||||||
// make_global_read_lock_block_commit
|
// make_global_read_lock_block_commit
|
||||||
#include "sql_base.h" // find_temporary_tablesx
|
#include "sql_base.h" // find_temporary_table
|
||||||
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
|
#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_*
|
||||||
#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
|
#include "sql_show.h" // mysqld_list_*, mysqld_show_*,
|
||||||
// calc_sum_of_all_status
|
// calc_sum_of_all_status
|
||||||
@ -44,7 +44,6 @@
|
|||||||
#include "sql_table.h" // mysql_create_like_table,
|
#include "sql_table.h" // mysql_create_like_table,
|
||||||
// mysql_create_table,
|
// mysql_create_table,
|
||||||
// mysql_alter_table,
|
// mysql_alter_table,
|
||||||
// mysql_recreate_table,
|
|
||||||
// mysql_backup_table,
|
// mysql_backup_table,
|
||||||
// mysql_restore_table
|
// mysql_restore_table
|
||||||
#include "sql_reload.h" // reload_acl_and_cache
|
#include "sql_reload.h" // reload_acl_and_cache
|
||||||
@ -124,6 +123,7 @@ static void sql_kill(THD *thd, ulong id, killed_state state);
|
|||||||
static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
|
static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
|
||||||
static bool execute_show_status(THD *, TABLE_LIST *);
|
static bool execute_show_status(THD *, TABLE_LIST *);
|
||||||
static bool execute_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
|
static bool execute_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
|
||||||
|
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables);
|
||||||
|
|
||||||
const char *any_db="*any*"; // Special symbol for check_access
|
const char *any_db="*any*"; // Special symbol for check_access
|
||||||
|
|
||||||
@ -499,6 +499,7 @@ void init_update_queries(void)
|
|||||||
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES;
|
||||||
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES;
|
||||||
sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES;
|
||||||
|
sql_command_flags[SQLCOM_HA_OPEN]|= CF_PREOPEN_TMP_TABLES;
|
||||||
sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES;
|
||||||
sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES;
|
||||||
sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
|
sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
|
||||||
@ -2413,6 +2414,7 @@ mysql_execute_command(THD *thd)
|
|||||||
if (open_temporary_tables(thd, all_tables))
|
if (open_temporary_tables(thd, all_tables))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (lex->sql_command) {
|
switch (lex->sql_command) {
|
||||||
|
|
||||||
case SQLCOM_SHOW_EVENTS:
|
case SQLCOM_SHOW_EVENTS:
|
||||||
@ -2422,8 +2424,7 @@ mysql_execute_command(THD *thd)
|
|||||||
#endif
|
#endif
|
||||||
case SQLCOM_SHOW_STATUS_PROC:
|
case SQLCOM_SHOW_STATUS_PROC:
|
||||||
case SQLCOM_SHOW_STATUS_FUNC:
|
case SQLCOM_SHOW_STATUS_FUNC:
|
||||||
if ((res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
|
if (lock_tables_precheck(thd, all_tables))
|
||||||
UINT_MAX, FALSE)))
|
|
||||||
goto error;
|
goto error;
|
||||||
res= execute_sqlcom_select(thd, all_tables);
|
res= execute_sqlcom_select(thd, all_tables);
|
||||||
break;
|
break;
|
||||||
@ -2798,12 +2799,6 @@ case SQLCOM_PREPARE:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
Close any open handlers for the table. We need to this extra call here
|
|
||||||
as there may have been new handlers created since the previous call.
|
|
||||||
*/
|
|
||||||
mysql_ha_rm_tables(thd, create_table);
|
|
||||||
|
|
||||||
if (select_lex->item_list.elements) // With select
|
if (select_lex->item_list.elements) // With select
|
||||||
{
|
{
|
||||||
select_result *result;
|
select_result *result;
|
||||||
@ -4173,6 +4168,9 @@ end_with_restore_list:
|
|||||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||||
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
|
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
|
||||||
goto error;
|
goto error;
|
||||||
|
/* Close temporary tables which were pre-opened for privilege checking. */
|
||||||
|
close_thread_tables(thd);
|
||||||
|
all_tables->table= NULL;
|
||||||
res= mysql_ha_open(thd, first_table, 0);
|
res= mysql_ha_open(thd, first_table, 0);
|
||||||
break;
|
break;
|
||||||
case SQLCOM_HA_CLOSE:
|
case SQLCOM_HA_CLOSE:
|
||||||
@ -5519,6 +5517,9 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
|
|||||||
if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
|
if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
|
||||||
return TRUE; /* Access denied */
|
return TRUE; /* Access denied */
|
||||||
|
|
||||||
|
close_thread_tables(thd);
|
||||||
|
dst_table->table= NULL;
|
||||||
|
|
||||||
/* Access granted */
|
/* Access granted */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -5604,10 +5605,10 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
|
|||||||
|
|
||||||
DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
|
DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
|
||||||
tables->view != 0));
|
tables->view != 0));
|
||||||
if (tables->is_anonymous_derived_table() ||
|
|
||||||
(tables->table && tables->table->s &&
|
if (tables->is_anonymous_derived_table())
|
||||||
(int)tables->table->s->tmp_table))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
thd->security_ctx= sctx;
|
thd->security_ctx= sctx;
|
||||||
|
|
||||||
if (check_access(thd, want_access, tables->get_db_name(),
|
if (check_access(thd, want_access, tables->get_db_name(),
|
||||||
@ -7465,6 +7466,19 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
|
|||||||
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
|
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
|
||||||
DBUG_ENTER("multi_delete_precheck");
|
DBUG_ENTER("multi_delete_precheck");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Temporary tables are pre-opened in 'tables' list only. Here we need to
|
||||||
|
initialize TABLE instances in 'aux_tables' list.
|
||||||
|
*/
|
||||||
|
for (TABLE_LIST *tl= aux_tables; tl; tl= tl->next_global)
|
||||||
|
{
|
||||||
|
if (tl->table)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tl->correspondent_table)
|
||||||
|
tl->table= tl->correspondent_table->table;
|
||||||
|
}
|
||||||
|
|
||||||
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
||||||
DBUG_ASSERT(aux_tables != 0);
|
DBUG_ASSERT(aux_tables != 0);
|
||||||
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
|
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
|
||||||
@ -7733,9 +7747,9 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
|||||||
CREATE TABLE ... SELECT, also require INSERT.
|
CREATE TABLE ... SELECT, also require INSERT.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
want_priv= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
||||||
CREATE_TMP_ACL : CREATE_ACL) |
|
CREATE_TMP_ACL :
|
||||||
(select_lex->item_list.elements ? INSERT_ACL : 0);
|
(CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
|
||||||
|
|
||||||
if (check_access(thd, want_priv, create_table->db,
|
if (check_access(thd, want_priv, create_table->db,
|
||||||
&create_table->grant.privilege,
|
&create_table->grant.privilege,
|
||||||
@ -7744,11 +7758,48 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* If it is a merge table, check privileges for merge children. */
|
/* If it is a merge table, check privileges for merge children. */
|
||||||
if (lex->create_info.merge_list.first &&
|
if (lex->create_info.merge_list.first)
|
||||||
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
{
|
||||||
|
/*
|
||||||
|
The user must have (SELECT_ACL | UPDATE_ACL | DELETE_ACL) on the
|
||||||
|
underlying base tables, even if there are temporary tables with the same
|
||||||
|
names.
|
||||||
|
|
||||||
|
From user's point of view, it might look as if the user must have these
|
||||||
|
privileges on temporary tables to create a merge table over them. This is
|
||||||
|
one of two cases when a set of privileges is required for operations on
|
||||||
|
temporary tables (see also CREATE TABLE).
|
||||||
|
|
||||||
|
The reason for this behavior stems from the following facts:
|
||||||
|
|
||||||
|
- For merge tables, the underlying table privileges are checked only
|
||||||
|
at CREATE TABLE / ALTER TABLE time.
|
||||||
|
|
||||||
|
In other words, once a merge table is created, the privileges of
|
||||||
|
the underlying tables can be revoked, but the user will still have
|
||||||
|
access to the merge table (provided that the user has privileges on
|
||||||
|
the merge table itself).
|
||||||
|
|
||||||
|
- Temporary tables shadow base tables.
|
||||||
|
|
||||||
|
I.e. there might be temporary and base tables with the same name, and
|
||||||
|
the temporary table takes the precedence in all operations.
|
||||||
|
|
||||||
|
- For temporary MERGE tables we do not track if their child tables are
|
||||||
|
base or temporary. As result we can't guarantee that privilege check
|
||||||
|
which was done in presence of temporary child will stay relevant later
|
||||||
|
as this temporary table might be removed.
|
||||||
|
|
||||||
|
If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for
|
||||||
|
the underlying *base* tables, it would create a security breach as in
|
||||||
|
Bug#12771903.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
|
||||||
lex->create_info.merge_list.first,
|
lex->create_info.merge_list.first,
|
||||||
FALSE, UINT_MAX, FALSE))
|
FALSE, UINT_MAX, FALSE))
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
if (want_priv != CREATE_TMP_ACL &&
|
if (want_priv != CREATE_TMP_ACL &&
|
||||||
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
|
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
|
||||||
@ -7773,6 +7824,35 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check privileges for LOCK TABLES statement.
|
||||||
|
|
||||||
|
@param thd Thread context.
|
||||||
|
@param tables List of tables to be locked.
|
||||||
|
|
||||||
|
@retval FALSE - Success.
|
||||||
|
@retval TRUE - Failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
|
||||||
|
|
||||||
|
for (TABLE_LIST *table= tables; table != first_not_own_table && table;
|
||||||
|
table= table->next_global)
|
||||||
|
{
|
||||||
|
if (is_temporary_table(table))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table,
|
||||||
|
FALSE, 1, FALSE))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
negate given expression.
|
negate given expression.
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ When one supplies long data for a placeholder:
|
|||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_cache.h"
|
#include "sp_cache.h"
|
||||||
|
#include "sql_handler.h" // mysql_ha_rm_tables
|
||||||
#include "probes_mysql.h"
|
#include "probes_mysql.h"
|
||||||
#ifdef EMBEDDED_LIBRARY
|
#ifdef EMBEDDED_LIBRARY
|
||||||
/* include MYSQL_BIND headers */
|
/* include MYSQL_BIND headers */
|
||||||
|
@ -142,7 +142,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout,
|
if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout,
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
0))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)
|
for (ren_table= table_list; ren_table; ren_table= ren_table->next_local)
|
||||||
|
@ -2073,14 +2073,12 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_ha_rm_tables(thd, tables);
|
|
||||||
|
|
||||||
if (!drop_temporary)
|
if (!drop_temporary)
|
||||||
{
|
{
|
||||||
if (!thd->locked_tables_mode)
|
if (!thd->locked_tables_mode)
|
||||||
{
|
{
|
||||||
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
|
if (lock_table_names(thd, tables, NULL,
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
thd->variables.lock_wait_timeout, 0))
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
for (table= tables; table; table= table->next_local)
|
for (table= tables; table; table= table->next_local)
|
||||||
{
|
{
|
||||||
@ -2206,6 +2204,9 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
|
|||||||
@note This function assumes that metadata locks have already been taken.
|
@note This function assumes that metadata locks have already been taken.
|
||||||
It is also assumed that the tables have been removed from TDC.
|
It is also assumed that the tables have been removed from TDC.
|
||||||
|
|
||||||
|
@note This function assumes that temporary tables to be dropped have
|
||||||
|
been pre-opened using corresponding table list elements.
|
||||||
|
|
||||||
@todo When logging to the binary log, we should log
|
@todo When logging to the binary log, we should log
|
||||||
tmp_tables and transactional tables as separate statements if we
|
tmp_tables and transactional tables as separate statements if we
|
||||||
are in a transaction; This is needed to get these tables into the
|
are in a transaction; This is needed to get these tables into the
|
||||||
@ -5060,6 +5061,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
|||||||
String query(buf, sizeof(buf), system_charset_info);
|
String query(buf, sizeof(buf), system_charset_info);
|
||||||
query.length(0); // Have to zero it since constructor doesn't
|
query.length(0); // Have to zero it since constructor doesn't
|
||||||
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
|
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
|
||||||
|
bool new_table= FALSE; // Whether newly created table is open.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The condition avoids a crash as described in BUG#48506. Other
|
The condition avoids a crash as described in BUG#48506. Other
|
||||||
@ -5068,14 +5070,21 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
|||||||
*/
|
*/
|
||||||
if (!table->view)
|
if (!table->view)
|
||||||
{
|
{
|
||||||
|
if (!table->table)
|
||||||
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Here we open the destination table, on which we already have
|
In order for store_create_info() to work we need to open
|
||||||
exclusive metadata lock. This is needed for store_create_info()
|
destination table if it is not already open (i.e. if it
|
||||||
to work. The table will be closed by close_thread_table() at
|
has not existed before). We don't need acquire metadata
|
||||||
the end of this branch.
|
lock in order to do this as we already hold exclusive
|
||||||
|
lock on this table. The table will be closed by
|
||||||
|
close_thread_table() at the end of this branch.
|
||||||
*/
|
*/
|
||||||
if (open_table(thd, table, thd->mem_root, &ot_ctx))
|
if (open_table(thd, table, thd->mem_root, &ot_ctx))
|
||||||
goto err;
|
goto err;
|
||||||
|
new_table= TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int result __attribute__((unused))=
|
int result __attribute__((unused))=
|
||||||
store_create_info(thd, table, &query,
|
store_create_info(thd, table, &query,
|
||||||
@ -5085,15 +5094,18 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
|||||||
if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
|
if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if (new_table)
|
||||||
|
{
|
||||||
DBUG_ASSERT(thd->open_tables == table->table);
|
DBUG_ASSERT(thd->open_tables == table->table);
|
||||||
/*
|
/*
|
||||||
When opening the table, we ignored the locked tables
|
When opening the table, we ignored the locked tables
|
||||||
(MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
|
(MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table
|
||||||
risking to close some locked table.
|
without risking to close some locked table.
|
||||||
*/
|
*/
|
||||||
close_thread_table(thd, &thd->open_tables);
|
close_thread_table(thd, &thd->open_tables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else // Case 1
|
else // Case 1
|
||||||
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
||||||
goto err;
|
goto err;
|
||||||
@ -8821,11 +8833,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
|
|||||||
if (! thd->in_sub_stmt)
|
if (! thd->in_sub_stmt)
|
||||||
trans_rollback_stmt(thd);
|
trans_rollback_stmt(thd);
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
/*
|
|
||||||
Don't release metadata locks, this will be done at
|
|
||||||
statement end.
|
|
||||||
*/
|
|
||||||
table->table=0; // For query cache
|
|
||||||
}
|
}
|
||||||
if (protocol->write())
|
if (protocol->write())
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -18,9 +18,8 @@
|
|||||||
#include "sql_class.h" // THD
|
#include "sql_class.h" // THD
|
||||||
#include "sql_base.h" // open_and_lock_tables
|
#include "sql_base.h" // open_and_lock_tables
|
||||||
#include "sql_table.h" // write_bin_log
|
#include "sql_table.h" // write_bin_log
|
||||||
#include "sql_handler.h" // mysql_ha_rm_tables
|
|
||||||
#include "datadict.h" // dd_recreate_table()
|
#include "datadict.h" // dd_recreate_table()
|
||||||
#include "lock.h" // MYSQL_OPEN_TEMPORARY_ONLY
|
#include "lock.h" // MYSQL_OPEN_* flags
|
||||||
#include "sql_acl.h" // DROP_ACL
|
#include "sql_acl.h" // DROP_ACL
|
||||||
#include "sql_parse.h" // check_one_table_access()
|
#include "sql_parse.h" // check_one_table_access()
|
||||||
#include "sql_truncate.h"
|
#include "sql_truncate.h"
|
||||||
@ -199,9 +198,7 @@ int Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* If it is a temporary table, no need to take locks. */
|
/* If it is a temporary table, no need to take locks. */
|
||||||
if (is_tmp_table)
|
if (!is_tmp_table)
|
||||||
flags= MYSQL_OPEN_TEMPORARY_ONLY;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* We don't need to load triggers. */
|
/* We don't need to load triggers. */
|
||||||
DBUG_ASSERT(table_ref->trg_event_map == 0);
|
DBUG_ASSERT(table_ref->trg_event_map == 0);
|
||||||
@ -216,7 +213,7 @@ int Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
|
|||||||
the MDL lock taken above and otherwise there is no way to
|
the MDL lock taken above and otherwise there is no way to
|
||||||
wait for FLUSH TABLES in deadlock-free fashion.
|
wait for FLUSH TABLES in deadlock-free fashion.
|
||||||
*/
|
*/
|
||||||
flags= MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_SKIP_TEMPORARY;
|
flags= MYSQL_OPEN_IGNORE_FLUSH;
|
||||||
/*
|
/*
|
||||||
Even though we have an MDL lock on the table here, we don't
|
Even though we have an MDL lock on the table here, we don't
|
||||||
pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables
|
pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables
|
||||||
@ -346,8 +343,7 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
|
|||||||
/* Acquire an exclusive lock. */
|
/* Acquire an exclusive lock. */
|
||||||
DBUG_ASSERT(table_ref->next_global == NULL);
|
DBUG_ASSERT(table_ref->next_global == NULL);
|
||||||
if (lock_table_names(thd, table_ref, NULL,
|
if (lock_table_names(thd, table_ref, NULL,
|
||||||
thd->variables.lock_wait_timeout,
|
thd->variables.lock_wait_timeout, 0))
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name,
|
if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name,
|
||||||
@ -399,26 +395,28 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
|
|||||||
bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
|
bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
TABLE *table;
|
|
||||||
bool binlog_stmt;
|
bool binlog_stmt;
|
||||||
DBUG_ENTER("Sql_cmd_truncate_table::truncate_table");
|
DBUG_ENTER("Sql_cmd_truncate_table::truncate_table");
|
||||||
|
|
||||||
|
DBUG_ASSERT((!table_ref->table) ||
|
||||||
|
(table_ref->table && table_ref->table->s));
|
||||||
|
|
||||||
/* Initialize, or reinitialize in case of reexecution (SP). */
|
/* Initialize, or reinitialize in case of reexecution (SP). */
|
||||||
m_ticket_downgrade= NULL;
|
m_ticket_downgrade= NULL;
|
||||||
|
|
||||||
/* Remove table from the HANDLER's hash. */
|
|
||||||
mysql_ha_rm_tables(thd, table_ref);
|
|
||||||
|
|
||||||
/* If it is a temporary table, no need to take locks. */
|
/* If it is a temporary table, no need to take locks. */
|
||||||
if ((table= find_temporary_table(thd, table_ref)))
|
if (is_temporary_table(table_ref))
|
||||||
{
|
{
|
||||||
|
TABLE *tmp_table= table_ref->table;
|
||||||
|
|
||||||
/* In RBR, the statement is not binlogged if the table is temporary. */
|
/* In RBR, the statement is not binlogged if the table is temporary. */
|
||||||
binlog_stmt= !thd->is_current_stmt_binlog_format_row();
|
binlog_stmt= !thd->is_current_stmt_binlog_format_row();
|
||||||
|
|
||||||
/* Note that a temporary table cannot be partitioned. */
|
/* Note that a temporary table cannot be partitioned. */
|
||||||
if (ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE))
|
if (ha_check_storage_engine_flag(tmp_table->s->db_type(),
|
||||||
|
HTON_CAN_RECREATE))
|
||||||
{
|
{
|
||||||
if ((error= recreate_temporary_table(thd, table)))
|
if ((error= recreate_temporary_table(thd, tmp_table)))
|
||||||
binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate. */
|
binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate. */
|
||||||
|
|
||||||
DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table);
|
DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table);
|
||||||
|
@ -1665,8 +1665,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout,
|
if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout, 0))
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY))
|
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
for (view= views; view; view= view->next_local)
|
for (view= views; view; view= view->next_local)
|
||||||
|
@ -484,6 +484,11 @@ int ha_myisammrg::add_children_list(void)
|
|||||||
/* Set the expected table version, to not cause spurious re-prepare. */
|
/* Set the expected table version, to not cause spurious re-prepare. */
|
||||||
child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
|
child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
|
||||||
mrg_child_def->get_child_def_version());
|
mrg_child_def->get_child_def_version());
|
||||||
|
/*
|
||||||
|
Copy parent's prelocking attribute to allow opening of child
|
||||||
|
temporary residing in the prelocking list.
|
||||||
|
*/
|
||||||
|
child_l->prelocking_placeholder= parent_l->prelocking_placeholder;
|
||||||
/*
|
/*
|
||||||
For statements which acquire a SNW metadata lock on a parent table and
|
For statements which acquire a SNW metadata lock on a parent table and
|
||||||
then later try to upgrade it to an X lock (e.g. ALTER TABLE), SNW
|
then later try to upgrade it to an X lock (e.g. ALTER TABLE), SNW
|
||||||
|
Loading…
x
Reference in New Issue
Block a user