summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc277
1 files changed, 199 insertions, 78 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f9554c79305..7d057f4e91a 100644
--- a/sql/sql_parse.cc
+++ b/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
@@ -499,6 +498,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;
@@ -512,7 +512,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;
@@ -888,7 +888,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);
@@ -1158,7 +1158,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();
@@ -1189,13 +1189,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);
@@ -1294,8 +1294,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
query_cache_end_of_result(thd);
mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
- thd->stmt_da->is_error() ? thd->stmt_da->sql_errno()
- : 0, command_name[command].str);
+ 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);
@@ -1331,10 +1333,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);
@@ -1427,6 +1429,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;
@@ -1451,7 +1456,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
@@ -1605,7 +1610,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;
}
@@ -1681,7 +1686,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();
@@ -2057,7 +2063,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,
@@ -2204,12 +2210,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
@@ -2405,6 +2411,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:
@@ -2412,13 +2443,6 @@ 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:
- 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);
@@ -2451,6 +2475,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:
@@ -2555,16 +2581,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:
@@ -2634,7 +2660,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)
{
@@ -2687,7 +2713,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);
@@ -2795,9 +2821,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;
@@ -2845,7 +2868,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' "
@@ -2882,7 +2905,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);
@@ -2992,7 +3015,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
@@ -3008,7 +3031,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)
{
@@ -3061,7 +3084,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);
@@ -3152,6 +3175,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
contains any table-specific privilege.
@@ -3329,6 +3359,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;
@@ -3668,6 +3710,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;
@@ -3970,7 +4025,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
@@ -4169,6 +4224,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:
@@ -4376,7 +4434,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();
}
@@ -4581,7 +4639,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;
@@ -4634,7 +4692,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. */
@@ -4651,7 +4709,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)
@@ -4889,10 +4947,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
@@ -4934,7 +4994,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)
@@ -4948,9 +5008,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);
@@ -4977,10 +5037,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())
@@ -5046,7 +5106,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)
@@ -5504,6 +5564,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,
@@ -5517,6 +5583,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;
}
@@ -5602,10 +5671,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(),
@@ -5811,7 +5880,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;
}
@@ -5879,7 +5948,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;
/*
@@ -5916,8 +5984,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;
@@ -6144,7 +6212,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)
{
@@ -6252,7 +6320,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();
@@ -6442,6 +6510,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;
@@ -6586,6 +6655,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);
@@ -7291,7 +7363,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;
}
@@ -7464,6 +7536,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))
@@ -7732,9 +7817,9 @@ 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.options & HA_LEX_CREATE_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,
@@ -7743,11 +7828,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))
@@ -8105,14 +8227,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. */
@@ -8129,7 +8250,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. */