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:
329
sql/sql_parse.cc
329
sql/sql_parse.cc
@ -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. */
|
||||
|
Reference in New Issue
Block a user