1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

Merge 10.0 to galera-10.0

This commit is contained in:
Jan Lindström
2013-09-03 17:50:36 +03:00
3269 changed files with 156036 additions and 54963 deletions

View File

@ -24,7 +24,7 @@
// set_handler_table_locks,
// lock_global_read_lock,
// 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_show.h" // mysqld_list_*, mysqld_show_*,
// calc_sum_of_all_status
@ -44,7 +44,6 @@
#include "sql_table.h" // mysql_create_like_table,
// mysql_create_table,
// mysql_alter_table,
// mysql_recreate_table,
// mysql_backup_table,
// mysql_restore_table
#include "sql_reload.h" // reload_acl_and_cache
@ -222,7 +221,7 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask)
case SQLCOM_ALTER_TABLE:
case SQLCOM_CREATE_TABLE:
/* If CREATE TABLE of non-temporary table, do implicit commit */
skip= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
skip= lex->create_info.tmp_table();
break;
case SQLCOM_SET_OPTION:
skip= lex->autocommit ? FALSE : TRUE;
@ -509,6 +508,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SELECT]|= 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_HA_OPEN]|= 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_ANALYZE]|= CF_PREOPEN_TMP_TABLES;
@ -522,7 +522,7 @@ void init_update_queries(void)
DDL statements that should start with closing opened handlers.
We use this flag only for statements for which open HANDLERs
have to be closed before emporary tables are pre-opened.
have to be closed before temporary tables are pre-opened.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE;
@ -920,7 +920,7 @@ bool do_command(THD *thd)
Consider moving to init_connect() instead.
*/
thd->clear_error(); // Clear error message
thd->stmt_da->reset_diagnostics_area();
thd->get_stmt_da()->reset_diagnostics_area();
net_new_transaction(net);
@ -1138,7 +1138,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
const my_bool create_temp_tables=
(lex->sql_command == SQLCOM_CREATE_TABLE) &&
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
lex->create_info.tmp_table();
const my_bool drop_temp_tables=
(lex->sql_command == SQLCOM_DROP_TABLE) &&
@ -1283,6 +1283,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->enable_slow_log= TRUE;
thd->query_plan_flags= QPLAN_INIT;
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
DEBUG_SYNC(thd,"dispatch_command_before_set_time");
thd->set_time();
if (!(server_command_flags[command] & CF_SKIP_QUERY_ID))
thd->set_query_id(next_query_id());
@ -1328,7 +1331,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_CHANGE_USER:
{
bool rc;
int auth_rc;
status_var_increment(thd->status_var.com_other);
thd->change_user();
@ -1359,13 +1362,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->failed_com_change_user >= 3)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
rc= 1;
auth_rc= 1;
}
else
rc= acl_authenticate(thd, 0, packet_length);
auth_rc= acl_authenticate(thd, 0, packet_length);
mysql_audit_notify_connection_change_user(thd);
if (rc)
if (auth_rc)
{
/* Free user if allocated by acl_authenticate */
my_free(thd->security_ctx->user);
@ -1466,6 +1469,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->update_server_status();
thd->protocol->end_statement();
query_cache_end_of_result(thd);
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
thd->get_stmt_da()->is_error()
? thd->get_stmt_da()->sql_errno()
: 0,
command_name[command].str);
ulong length= (ulong)(packet_end - beginning_of_next_stmt);
log_slow_statement(thd);
@ -1500,10 +1510,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(char *) thd->security_ctx->host_or_ip);
/* PSI begin */
thd->m_statement_psi=
MYSQL_START_STATEMENT(&thd->m_statement_state,
com_statement_info[command].m_key,
thd->db, thd->db_length);
thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
com_statement_info[command].m_key,
thd->db, thd->db_length,
thd->charset());
THD_STAGE_INFO(thd, stage_init);
MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt,
length);
@ -1605,6 +1615,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->set_query(fields, query_length);
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (open_temporary_tables(thd, &table_list))
break;
if (check_table_access(thd, SELECT_ACL, &table_list,
TRUE, UINT_MAX, FALSE))
break;
@ -1629,7 +1642,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* We don't calculate statistics for this command */
general_log_print(thd, command, NullS);
net->error=0; // Don't give 'abort' message
thd->stmt_da->disable_status(); // Don't send anything back
thd->get_stmt_da()->disable_status(); // Don't send anything back
error=TRUE; // End server
break;
#ifndef EMBEDDED_LIBRARY
@ -1675,7 +1688,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
lex_start(thd);
status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0];
ulonglong options= (ulonglong) (uchar) packet[0];
if (trans_commit_implicit(thd))
break;
thd->mdl_context.release_transactional_locks();
@ -1773,8 +1786,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(int) thread_count, (ulong) thd->query_id,
current_global_status_var->long_query_count,
current_global_status_var->opened_tables,
refresh_version,
cached_open_tables(),
tdc_refresh_version(),
tc_records(),
(uint) (queries_per_second1000 / 1000),
(uint) (queries_per_second1000 % 1000));
#ifdef EMBEDDED_LIBRARY
@ -1783,7 +1796,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#else
(void) my_net_write(net, (uchar*) buff, length);
(void) net_flush(net);
thd->stmt_da->disable_status();
thd->get_stmt_da()->disable_status();
#endif
break;
}
@ -1879,7 +1892,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0);
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
thd->stmt_da->is_error() ? thd->stmt_da->sql_errno() : 0,
thd->get_stmt_da()->is_error() ?
thd->get_stmt_da()->sql_errno() : 0,
command_name[command].str);
thd->update_all_stats();
@ -1895,6 +1909,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
thd->m_statement_psi= NULL;
thd->set_time();
dec_thread_running();
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
@ -2254,7 +2269,7 @@ bool sp_process_definer(THD *thd)
if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
{
push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_NOTE,
Sql_condition::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,
ER(ER_NO_SUCH_USER),
lex->definer->user.str,
@ -2401,12 +2416,12 @@ mysql_execute_command(THD *thd)
variables, but for now this is probably good enough.
*/
if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0)
thd->warning_info->set_read_only(TRUE);
thd->get_stmt_da()->set_warning_info_read_only(TRUE);
else
{
thd->warning_info->set_read_only(FALSE);
thd->get_stmt_da()->set_warning_info_read_only(FALSE);
if (all_tables)
thd->warning_info->opt_clear_warning_info(thd->query_id);
thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
}
#ifdef HAVE_REPLICATION
@ -2661,6 +2676,31 @@ mysql_execute_command(THD *thd)
goto error;
}
/*
Close tables open by HANDLERs before executing DDL statement
which is going to affect those tables.
This should happen before temporary tables are pre-opened as
otherwise we will get errors about attempt to re-open tables
if table to be changed is open through HANDLER.
Note that even although this is done before any privilege
checks there is no security problem here as closing open
HANDLER doesn't require any privileges anyway.
*/
if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE)
mysql_ha_rm_tables(thd, all_tables);
/*
Pre-open temporary tables to simplify privilege checking
for statements which need this.
*/
if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES)
{
if (open_temporary_tables(thd, all_tables))
goto error;
}
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@ -2668,16 +2708,9 @@ mysql_execute_command(THD *thd)
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
break;
#endif
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
#ifdef WITH_WSREP
if (WSREP_CLIENT(thd) && wsrep_causal_wait(thd)) goto error;
#endif /* WITH_WSREP */
if ((res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
goto error;
res= execute_sqlcom_select(thd, all_tables);
break;
case SQLCOM_SHOW_STATUS:
{
execute_show_status(thd, all_tables);
@ -2710,6 +2743,8 @@ mysql_execute_command(THD *thd)
}
/* no break; fall through */
}
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TRIGGERS:
@ -2824,16 +2859,16 @@ case SQLCOM_PREPARE:
case SQLCOM_SHOW_WARNS:
{
res= mysqld_show_warnings(thd, (ulong)
((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
(1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
(1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
((1L << (uint) Sql_condition::WARN_LEVEL_NOTE) |
(1L << (uint) Sql_condition::WARN_LEVEL_WARN) |
(1L << (uint) Sql_condition::WARN_LEVEL_ERROR)
));
break;
}
case SQLCOM_SHOW_ERRORS:
{
res= mysqld_show_warnings(thd, (ulong)
(1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
(1L << (uint) Sql_condition::WARN_LEVEL_ERROR));
break;
}
case SQLCOM_SHOW_PROFILES:
@ -2903,7 +2938,7 @@ case SQLCOM_PREPARE:
mysql_mutex_lock(&LOCK_active_mi);
mi= master_info_index->get_master_info(&lex_mi->connection_name,
MYSQL_ERROR::WARN_LEVEL_NOTE);
Sql_condition::WARN_LEVEL_NOTE);
if (mi == NULL)
{
@ -2956,7 +2991,7 @@ case SQLCOM_PREPARE:
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
Master_info *mi;
mi= master_info_index->get_master_info(&lex_mi->connection_name,
MYSQL_ERROR::WARN_LEVEL_ERROR);
Sql_condition::WARN_LEVEL_ERROR);
if (mi != NULL)
{
res= show_master_info(thd, mi, 0);
@ -3064,9 +3099,6 @@ case SQLCOM_PREPARE:
}
#endif
/* Close any open handlers for the table. */
mysql_ha_rm_tables(thd, create_table);
if (select_lex->item_list.elements) // With select
{
select_result *result;
@ -3114,7 +3146,7 @@ case SQLCOM_PREPARE:
*/
if (splocal_refs != thd->query_name_consts)
push_warning(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR,
"Invoked routine ran a statement that may cause problems with "
"binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
@ -3151,7 +3183,7 @@ case SQLCOM_PREPARE:
{
if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR,
ER(ER_TABLE_EXISTS_ERROR),
create_info.alias);
@ -3173,7 +3205,7 @@ case SQLCOM_PREPARE:
lex->unlink_first_table(&link_to_local);
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG;
/*
@ -3202,7 +3234,7 @@ case SQLCOM_PREPARE:
else
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG;
/* regular create */
#ifdef WITH_WSREP
@ -3268,7 +3300,7 @@ end_with_restore_list:
res= mysql_alter_table(thd, first_table->db, first_table->table_name,
&create_info, first_table, &alter_info,
0, (ORDER*) 0, 0, 0);
0, (ORDER*) 0, 0);
break;
}
#ifdef HAVE_REPLICATION
@ -3284,7 +3316,7 @@ end_with_restore_list:
if ((mi= (master_info_index->
get_master_info(&lex_mi->connection_name,
MYSQL_ERROR::WARN_LEVEL_ERROR))))
Sql_condition::WARN_LEVEL_ERROR))))
{
if (load_error)
{
@ -3337,7 +3369,7 @@ end_with_restore_list:
mysql_mutex_lock(&LOCK_active_mi);
if ((mi= (master_info_index->
get_master_info(&lex_mi->connection_name,
MYSQL_ERROR::WARN_LEVEL_ERROR))))
Sql_condition::WARN_LEVEL_ERROR))))
if (!stop_slave(thd, mi, 1/* net report*/))
my_ok(thd);
mysql_mutex_unlock(&LOCK_active_mi);
@ -3432,6 +3464,13 @@ end_with_restore_list:
}
else
{
/*
Temporary tables should be opened for SHOW CREATE TABLE, but not
for SHOW CREATE VIEW.
*/
if (open_temporary_tables(thd, all_tables))
goto error;
/*
The fact that check_some_access() returned FALSE does not mean that
access is granted. We need to check if first_table->grant.privilege
@ -3614,6 +3653,18 @@ end_with_restore_list:
case SQLCOM_INSERT:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/*
Since INSERT DELAYED doesn't support temporary tables, we could
not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE.
Open them here instead.
*/
if (first_table->lock_type != TL_WRITE_DELAYED)
{
if ((res= open_temporary_tables(thd, all_tables)))
break;
}
if ((res= insert_precheck(thd, all_tables)))
break;
@ -3973,6 +4024,19 @@ end_with_restore_list:
thd->mdl_context.release_transactional_locks();
if (res)
goto error;
/*
Here we have to pre-open temporary tables for LOCK TABLES.
CF_PREOPEN_TMP_TABLES is not set for this SQL statement simply
because LOCK TABLES calls close_thread_tables() as a first thing
(it's called from unlock_locked_tables() above). So even if
CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened
in a usual way, they would have been closed.
*/
if (open_temporary_tables(thd, all_tables))
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error;
@ -4286,7 +4350,7 @@ end_with_restore_list:
goto error;
if (specialflag & SPECIAL_NO_RESOLVE &&
hostname_requires_resolving(user->host.str))
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_HOSTNAME_WONT_WORK,
ER(ER_WARN_HOSTNAME_WONT_WORK));
// Are we trying to change a password of another user
@ -4458,6 +4522,17 @@ end_with_restore_list:
lex->kill_signal);
break;
}
case SQLCOM_SHUTDOWN:
#ifndef EMBEDDED_LIBRARY
if (check_global_access(thd,SHUTDOWN_ACL))
goto error;
kill_mysql();
my_ok(thd);
#else
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
#endif
break;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
{
@ -4477,6 +4552,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE))
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);
break;
case SQLCOM_HA_CLOSE:
@ -4705,7 +4783,7 @@ end_with_restore_list:
{
if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
lex->sql_command == SQLCOM_CREATE_PROCEDURE))
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL));
thd->clear_error();
}
@ -4911,7 +4989,7 @@ create_sp_error:
{
if (lex->check_exists)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
"FUNCTION (UDF)", lex->spname->m_name.str);
res= FALSE;
@ -4965,7 +5043,7 @@ create_sp_error:
sp_revoke_privileges(thd, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE))
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_PROC_AUTO_REVOKE_FAIL,
ER(ER_PROC_AUTO_REVOKE_FAIL));
/* If this happens, an error should have been reported. */
@ -4982,7 +5060,7 @@ create_sp_error:
if (lex->check_exists)
{
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
SP_COM_STRING(lex), lex->spname->m_qname.str);
if (!res)
@ -5226,10 +5304,12 @@ create_sp_error:
/* fall through */
case SQLCOM_SIGNAL:
case SQLCOM_RESIGNAL:
DBUG_ASSERT(lex->m_stmt != NULL);
res= lex->m_stmt->execute(thd);
case SQLCOM_GET_DIAGNOSTICS:
DBUG_ASSERT(lex->m_sql_cmd != NULL);
res= lex->m_sql_cmd->execute(thd);
break;
default:
#ifndef EMBEDDED_LIBRARY
DBUG_ASSERT(0); /* Impossible */
#endif
@ -5271,7 +5351,7 @@ finish:
if (thd->killed_errno())
{
/* If we already sent 'ok', we can ignore any kill query statements */
if (! thd->stmt_da->is_set())
if (! thd->get_stmt_da()->is_set())
thd->send_kill_message();
}
if (thd->killed < KILL_CONNECTION)
@ -5285,9 +5365,9 @@ finish:
else
{
/* If commit fails, we should be able to reset the OK status. */
thd->stmt_da->can_overwrite_status= TRUE;
thd->get_stmt_da()->set_overwrite_status(true);
trans_commit_stmt(thd);
thd->stmt_da->can_overwrite_status= FALSE;
thd->get_stmt_da()->set_overwrite_status(false);
}
#ifdef WITH_ARIA_STORAGE_ENGINE
ha_maria::implicit_commit(thd, FALSE);
@ -5317,10 +5397,10 @@ finish:
/* No transaction control allowed in sub-statements. */
DBUG_ASSERT(! thd->in_sub_stmt);
/* If commit fails, we should be able to reset the OK status. */
thd->stmt_da->can_overwrite_status= TRUE;
thd->get_stmt_da()->set_overwrite_status(true);
/* Commit the normal transaction if one is active. */
trans_commit_implicit(thd);
thd->stmt_da->can_overwrite_status= FALSE;
thd->get_stmt_da()->set_overwrite_status(false);
thd->mdl_context.release_transactional_locks();
}
else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
@ -5387,7 +5467,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
mysqld_show_warnings().
*/
thd->lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_YES, str.c_ptr_safe());
}
if (res)
@ -5848,6 +5928,12 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
DBUG_ASSERT(dst_table);
/*
Open temporary tables to be able to detect them during privilege check.
*/
if (open_temporary_tables(thd, dst_table))
return TRUE;
if (check_access(thd, SELECT_ACL, dst_table->db,
&dst_table->grant.privilege,
&dst_table->grant.m_internal,
@ -5861,6 +5947,9 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE))
return TRUE; /* Access denied */
close_thread_tables(thd);
dst_table->table= NULL;
/* Access granted */
return FALSE;
}
@ -5946,10 +6035,10 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
tables->view != 0));
if (tables->is_anonymous_derived_table() ||
(tables->table && tables->table->s &&
(int)tables->table->s->tmp_table))
if (tables->is_anonymous_derived_table())
continue;
thd->security_ctx= sctx;
if (check_access(thd, want_access, tables->get_db_name(),
@ -6155,7 +6244,7 @@ bool check_stack_overrun(THD *thd, long margin,
return 1;
}
#ifndef DBUG_OFF
max_stack_used= max(max_stack_used, stack_used);
max_stack_used= MY_MAX(max_stack_used, stack_used);
#endif
return 0;
}
@ -6223,7 +6312,6 @@ void THD::reset_for_next_command(bool calculate_userstat)
DBUG_ENTER("mysql_reset_thd_for_next_command");
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
DBUG_ASSERT(! thd->in_sub_stmt);
DBUG_ASSERT(thd->transaction.on);
thd->free_list= 0;
thd->select_number= 1;
/*
@ -6275,8 +6363,8 @@ void THD::reset_for_next_command(bool calculate_userstat)
thd->user_var_events_alloc= thd->mem_root;
}
thd->clear_error();
thd->stmt_da->reset_diagnostics_area();
thd->warning_info->reset_for_next_command();
thd->get_stmt_da()->reset_diagnostics_area();
thd->get_stmt_da()->reset_for_next_command();
thd->rand_used= 0;
thd->m_sent_row_count= thd->m_examined_row_count= 0;
thd->accessed_rows_and_keys= 0;
@ -6461,15 +6549,15 @@ void mysql_init_multi_delete(LEX *lex)
void wsrep_replay_transaction(THD *thd)
{
/* checking if BF trx must be replayed */
if (thd->wsrep_conflict_state== MUST_REPLAY)
if (thd->wsrep_conflict_state== MUST_REPLAY)
{
if (thd->wsrep_exec_mode!= REPL_RECV)
if (thd->wsrep_exec_mode!= REPL_RECV)
{
if (thd->stmt_da->is_sent)
if (thd->get_stmt_da()->is_sent())
{
WSREP_ERROR("replay issue, thd has reported status already");
}
thd->stmt_da->reset_diagnostics_area();
thd->get_stmt_da()->reset_diagnostics_area();
thd->wsrep_conflict_state= REPLAYING;
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
@ -6507,11 +6595,11 @@ void wsrep_replay_transaction(THD *thd)
case WSREP_OK:
thd->wsrep_conflict_state= NO_CONFLICT;
wsrep->post_commit(wsrep, &thd->wsrep_trx_handle);
WSREP_DEBUG("trx_replay successful for: %ld %llu",
WSREP_DEBUG("trx_replay successful for: %ld %llu",
thd->thread_id, (long long)thd->real_id);
break;
case WSREP_TRX_FAIL:
if (thd->stmt_da->is_sent)
if (thd->get_stmt_da()->is_sent())
{
WSREP_ERROR("replay failed, thd has reported status");
}
@ -6619,9 +6707,9 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
{
WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s",
thd->wsrep_conflict_state,
thd->stmt_da->is_sent,
thd->get_stmt_da()->is_sent(),
thd->killed,
thd->stmt_da->is_error() ? thd->stmt_da->sql_errno() : 0,
thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0,
thd->wsrep_retry_query);
my_free(thd->wsrep_retry_query);
thd->wsrep_retry_query = NULL;
@ -6676,7 +6764,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
{
LEX *lex= thd->lex;
bool err= parse_sql(thd, parser_state, NULL);
bool err= parse_sql(thd, parser_state, NULL, true);
if (!err)
{
@ -6784,7 +6872,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length)
lex_start(thd);
mysql_reset_thd_for_next_command(thd, opt_userstat_running);
if (!parse_sql(thd, & parser_state, NULL) &&
if (!parse_sql(thd, & parser_state, NULL, true) &&
all_tables_not_ok(thd, lex->select_lex.table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
@ -6974,6 +7062,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
thr_lock_type lock_type,
enum_mdl_type mdl_type,
List<Index_hint> *index_hints_arg,
List<String> *partition_names,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
@ -7118,6 +7207,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
*/
table_list.link_in_list(ptr, &ptr->next_local);
ptr->next_name_resolution_table= NULL;
#ifdef WITH_PARTITION_STORAGE_ENGINE
ptr->partition_names= partition_names;
#endif /* WITH_PARTITION_STORAGE_ENGINE */
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
@ -7252,6 +7344,8 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
for (uint i=0; i < 2; i++)
{
TABLE_LIST *table= join_list->pop();
if (!table)
DBUG_RETURN(NULL);
table->join_list= embedded_list;
table->embedding= ptr;
embedded_list->push_back(table);
@ -7827,7 +7921,7 @@ bool check_simple_select()
char command[80];
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
strmake(command, lip->yylval->symbol.str,
min(lip->yylval->symbol.length, sizeof(command)-1));
MY_MIN(lip->yylval->symbol.length, sizeof(command)-1));
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
return 1;
}
@ -8000,6 +8094,19 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
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 */
DBUG_ASSERT(aux_tables != 0);
if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE))
@ -8222,7 +8329,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex)
{
TABLE_LIST *create_table= lex->query_tables;
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
if (lex->create_info.tmp_table())
create_table->open_type= OT_TEMPORARY_ONLY;
else
create_table->open_type= OT_BASE_ONLY;
@ -8268,9 +8375,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
CREATE TABLE ... SELECT, also require INSERT.
*/
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL) |
(select_lex->item_list.elements ? INSERT_ACL : 0);
want_priv= lex->create_info.tmp_table() ? CREATE_TMP_ACL :
(CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
if (check_access(thd, want_priv, create_table->db,
&create_table->grant.privilege,
@ -8279,11 +8385,48 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
goto err;
/* If it is a merge table, check privileges for merge children. */
if (lex->create_info.merge_list.first &&
check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
lex->create_info.merge_list.first,
FALSE, UINT_MAX, FALSE))
goto err;
if (lex->create_info.merge_list.first)
{
/*
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,
FALSE, UINT_MAX, FALSE))
goto err;
}
if (want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table, FALSE, 1, FALSE))
@ -8956,7 +9099,8 @@ void wsrep_rollback_process(THD *thd)
DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting"));
DBUG_VOID_RETURN;
}
extern
extern
int wsrep_thd_is_brute_force(void *thd_ptr)
{
if (thd_ptr) {
@ -9230,14 +9374,13 @@ extern int MYSQLparse(void *thd); // from sql_yacc.cc
@retval TRUE on parsing error.
*/
bool parse_sql(THD *thd,
Parser_state *parser_state,
Object_creation_ctx *creation_ctx)
bool parse_sql(THD *thd, Parser_state *parser_state,
Object_creation_ctx *creation_ctx, bool do_pfs_digest)
{
bool ret_value;
DBUG_ENTER("parse_sql");
DBUG_ASSERT(thd->m_parser_state == NULL);
DBUG_ASSERT(thd->lex->m_stmt == NULL);
DBUG_ASSERT(thd->lex->m_sql_cmd == NULL);
MYSQL_QUERY_PARSE_START(thd->query());
/* Backup creation context. */
@ -9254,7 +9397,7 @@ bool parse_sql(THD *thd,
#ifdef HAVE_PSI_STATEMENT_DIGEST_INTERFACE
/* Start Digest */
thd->m_parser_state->m_lip.m_digest_psi=
MYSQL_DIGEST_START(thd->m_statement_psi);
MYSQL_DIGEST_START(do_pfs_digest ? thd->m_statement_psi : NULL);
#endif
/* Parse the query. */