diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 583 |
1 files changed, 375 insertions, 208 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index de106918178..3244467b19c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -21,12 +21,14 @@ #include <m_ctype.h> #include <myisam.h> #include <my_dir.h> +#include "rpl_handler.h" #include "sp_head.h" #include "sp.h" #include "sp_cache.h" #include "events.h" #include "sql_trigger.h" +#include "sql_prepare.h" #include "probes_mysql.h" /** @@ -45,7 +47,6 @@ "FUNCTION" : "PROCEDURE") static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); -static bool check_show_create_table_access(THD *thd, TABLE_LIST *table); const char *any_db="*any*"; // Special symbol for check_access @@ -307,13 +308,12 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_COLUMN_TYPES]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; + sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND; @@ -382,7 +382,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, Vio* save_vio; ulong save_client_capabilities; -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); thd->profiling.set_query_source(init_command_var->value, init_command_var->value_length); @@ -410,7 +410,7 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, thd->client_capabilities= save_client_capabilities; thd->net.vio= save_vio; -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); #endif } @@ -460,7 +460,7 @@ static void handle_bootstrap_impl(THD *thd) /* purecov: begin tested */ if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) { - net_end_statement(thd); + thd->protocol->end_statement(); bootstrap_error= 1; break; } @@ -485,8 +485,8 @@ static void handle_bootstrap_impl(THD *thd) thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); thd->set_query(query, length); - DBUG_PRINT("query",("%-.4096s", thd->query())); -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + DBUG_PRINT("query",("%-.4096s",thd->query())); +#if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); thd->profiling.set_query_source(thd->query(), length); #endif @@ -501,9 +501,9 @@ static void handle_bootstrap_impl(THD *thd) close_thread_tables(thd); // Free tables bootstrap_error= thd->is_error(); - net_end_statement(thd); + thd->protocol->end_statement(); -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); #endif @@ -596,7 +596,7 @@ static bool check_merge_table_access(THD *thd, char *db, tlist->db= db; /* purecov: inspected */ } error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - table_list, UINT_MAX, FALSE); + table_list, FALSE, UINT_MAX, FALSE); } return error; } @@ -808,12 +808,12 @@ bool do_command(THD *thd) Consider moving to init_connect() instead. */ thd->clear_error(); // Clear error message - thd->main_da.reset_diagnostics_area(); + thd->stmt_da->reset_diagnostics_area(); net_new_transaction(net); packet_length= my_net_read(net); -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); #endif if (packet_length == packet_error) @@ -826,7 +826,7 @@ bool do_command(THD *thd) /* The error must be set. */ DBUG_ASSERT(thd->is_error()); - net_end_statement(thd); + thd->protocol->end_statement(); if (net->error != 3) { @@ -873,7 +873,7 @@ bool do_command(THD *thd) return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); out: -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); #endif DBUG_RETURN(return_value); @@ -1071,7 +1071,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, tbl_name= strmake(db.str, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); if (mysql_table_dump(thd, &db, tbl_name) == 0) - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); break; } case COM_CHANGE_USER: @@ -1230,7 +1230,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, general_log_write(thd, command, thd->query(), thd->query_length()); DBUG_PRINT("query",("%-.4096s",thd->query())); -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.set_query_source(thd->query(), thd->query_length()); #endif @@ -1243,7 +1243,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { char *beginning_of_next_stmt= (char*) end_of_stmt; - net_end_statement(thd); + thd->protocol->end_statement(); query_cache_end_of_result(thd); /* Multiple queries exits, execute them individually @@ -1265,7 +1265,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, MYSQL_QUERY_DONE(thd->is_error()); } -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.finish_current_query(); thd->profiling.start_new_query("continuing"); thd->profiling.set_query_source(beginning_of_next_stmt, length); @@ -1341,7 +1341,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege, 0, 0, test(table_list.schema_table))) break; - if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0)) + if (check_grant(thd, SELECT_ACL, &table_list, TRUE, UINT_MAX, FALSE)) break; /* init structures for VIEW processing */ table_list.select_lex= &(thd->lex->select_lex); @@ -1366,7 +1366,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->main_da.disable_status(); // Don't send anything back + thd->stmt_da->disable_status(); // Don't send anything back error=TRUE; // End server break; @@ -1555,7 +1555,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #ifndef EMBEDDED_LIBRARY VOID(my_net_write(net, (uchar*) buff, length)); VOID(net_flush(net)); - thd->main_da.disable_status(); + thd->stmt_da->disable_status(); #endif break; } @@ -1621,7 +1621,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* report error issued during command execution */ if (thd->killed_errno()) { - if (! thd->main_da.is_set()) + if (! thd->stmt_da->is_set()) thd->send_kill_message(); } if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) @@ -1631,13 +1631,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } /* If commit fails, we should be able to reset the OK status. */ - thd->main_da.can_overwrite_status= TRUE; + thd->stmt_da->can_overwrite_status= TRUE; ha_autocommit_or_rollback(thd, thd->is_error()); - thd->main_da.can_overwrite_status= FALSE; + thd->stmt_da->can_overwrite_status= FALSE; thd->transaction.stmt.reset(); - net_end_statement(thd); + thd->protocol->end_statement(); query_cache_end_of_result(thd); thd->proc_info= "closing tables"; @@ -1684,9 +1684,9 @@ void log_slow_statement(THD *thd) /* Do not log administrative statements unless the appropriate option is - set; do not log into slow log if reading from backup. + set. */ - if (thd->enable_slow_log && !thd->user_time) + if (thd->enable_slow_log) { ulonglong end_utime_of_query= thd->current_utime(); thd_proc_info(thd, "logging slow query"); @@ -1807,7 +1807,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, Mark this current profiling record to be discarded. We don't wish to have SHOW commands show up in profiling. */ -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.discard_current_query(); #endif break; @@ -2075,8 +2075,14 @@ mysql_execute_command(THD *thd) variables, but for now this is probably good enough. Don't reset warnings when executing a stored routine. */ - if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont) - mysql_reset_errors(thd, 0); + if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0) + thd->warning_info->set_read_only(TRUE); + else + { + thd->warning_info->set_read_only(FALSE); + if (all_tables) + thd->warning_info->opt_clear_warning_info(thd->query_id); + } #ifdef HAVE_REPLICATION if (unlikely(thd->slave_thread)) @@ -2216,14 +2222,16 @@ mysql_execute_command(THD *thd) #endif case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: - if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))) + if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE, + UINT_MAX, FALSE))) res= execute_sqlcom_select(thd, all_tables); break; case SQLCOM_SHOW_STATUS: { system_status_var old_status_var= thd->status_var; thd->initial_status_var= &old_status_var; - if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))) + if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE, + UINT_MAX, FALSE))) res= execute_sqlcom_select(thd, all_tables); /* Don't log SHOW STATUS commands to slow query log */ thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | @@ -2253,18 +2261,22 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: case SQLCOM_SELECT: + { thd->status_var.last_query_cost= 0.0; + + /* + lex->exchange != NULL implies SELECT .. INTO OUTFILE and this + requires FILE_ACL access. + */ + ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL : + SELECT_ACL; + if (all_tables) - { res= check_table_access(thd, - lex->exchange ? SELECT_ACL | FILE_ACL : - SELECT_ACL, - all_tables, UINT_MAX, FALSE); - } + privileges_requested, + all_tables, FALSE, UINT_MAX, FALSE); else - res= check_access(thd, - lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, - any_db, 0, 0, 0, 0); + res= check_access(thd, privileges_requested, any_db, 0, 0, 0, UINT_MAX); if (res) break; @@ -2275,7 +2287,8 @@ mysql_execute_command(THD *thd) res= execute_sqlcom_select(thd, all_tables); break; - case SQLCOM_PREPARE: + } +case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); break; @@ -2291,8 +2304,8 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_DO: - if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables)) + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) + || open_and_lock_tables(thd, all_tables)) goto error; res= mysql_do(thd, *lex->insert_list); @@ -2356,7 +2369,7 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_PROFILES: { -#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) +#if defined(ENABLED_PROFILING) thd->profiling.discard_current_query(); res= thd->profiling.show_profiles(); if (res) @@ -2389,6 +2402,7 @@ mysql_execute_command(THD *thd) res = show_slave_hosts(thd); break; } + case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */ case SQLCOM_SHOW_BINLOG_EVENTS: { if (check_global_access(thd, REPL_SLAVE_ACL)) @@ -2401,8 +2415,8 @@ mysql_execute_command(THD *thd) case SQLCOM_BACKUP_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || - check_global_access(thd, FILE_ACL)) + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) + || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_backup_table(thd, first_table); @@ -2413,8 +2427,8 @@ mysql_execute_command(THD *thd) case SQLCOM_RESTORE_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) || - check_global_access(thd, FILE_ACL)) + if (check_table_access(thd, INSERT_ACL, all_tables, FALSE, UINT_MAX, FALSE) + || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_restore_table(thd, first_table); @@ -2513,7 +2527,7 @@ mysql_execute_command(THD *thd) test(first_table->schema_table))) goto error; /* purecov: inspected */ /* Check that the first table has CREATE privilege */ - if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0)) + if (check_grant(thd, CREATE_ACL, all_tables, FALSE, 1, FALSE)) goto error; pthread_mutex_lock(&LOCK_active_mi); @@ -2883,7 +2897,7 @@ end_with_restore_list: (TABLE_LIST *) create_info.merge_list.first)) goto error; /* purecov: inspected */ - if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0)) + if (check_grant(thd, priv_needed, all_tables, FALSE, UINT_MAX, FALSE)) goto error; if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) { // Rename of table @@ -2892,8 +2906,8 @@ end_with_restore_list: tmp_table.table_name= lex->name.str; tmp_table.db=select_lex->db; tmp_table.grant.privilege=priv; - if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, - UINT_MAX, 0)) + if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE, + UINT_MAX, FALSE)) goto error; } @@ -2947,10 +2961,11 @@ end_with_restore_list: */ old_list= table[0]; new_list= table->next_local[0]; - if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) || + if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) || (!test_all_bits(table->next_local->grant.privilege, INSERT_ACL | CREATE_ACL) && - check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0))) + check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, FALSE, 1, + FALSE))) goto error; } @@ -2981,11 +2996,75 @@ end_with_restore_list: goto error; #else { - /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ + /* + Access check: + SHOW CREATE TABLE require any privileges on the table level (ie + effecting all columns in the table). + SHOW CREATE VIEW require the SHOW_VIEW and SELECT ACLs on the table + level. + NOTE: SHOW_VIEW ACL is checked when the view is created. + */ + if (lex->only_view) + { + if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE)) + { + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "SHOW", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, first_table->alias); + goto error; + } + + /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ first_table->skip_temporary= 1; - if (check_show_create_table_access(thd, first_table)) - goto error; + } + else + { + ulong save_priv; + + /* + If it is an INFORMATION_SCHEMA table, SELECT_ACL privilege is the + only privilege allowed. For any other privilege check_access() + reports an error. That's how internal implementation protects + INFORMATION_SCHEMA from updates. + + For ordinary tables any privilege from the SHOW_CREATE_TABLE_ACLS + set is sufficient. + */ + + ulong check_privs= test(first_table->schema_table) ? + SELECT_ACL : SHOW_CREATE_TABLE_ACLS; + + if (check_access(thd, check_privs, first_table->db, + &save_priv, FALSE, FALSE, + test(first_table->schema_table))) + goto error; + + /* + save_priv contains any privileges actually granted by check_access + (i.e. save_priv contains global (user- and database-level) + privileges). + + The fact that check_access() returned FALSE does not mean that + access is granted. We need to check if save_priv contains any + table-specific privilege. If not, we need to check table-level + privileges. + + If there are no global privileges and no table-level privileges, + access is denied. + */ + + if (!(save_priv & (SHOW_CREATE_TABLE_ACLS)) && + !has_any_table_level_privileges(thd, SHOW_CREATE_TABLE_ACLS, first_table)) + { + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "SHOW", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, first_table->alias); + goto error; + } + } + + /* Access is granted. Execute the command. */ res= mysqld_show_create(thd, first_table); break; } @@ -2993,8 +3072,8 @@ end_with_restore_list: case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, - UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, all_tables, + FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ res = mysql_checksum_table(thd, first_table, &lex->check_opt); break; @@ -3003,7 +3082,7 @@ end_with_restore_list: { DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - UINT_MAX, FALSE)) + FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_repair_table(thd, first_table, &lex->check_opt); @@ -3022,8 +3101,8 @@ end_with_restore_list: case SQLCOM_CHECK: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, - UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, all_tables, + TRUE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_check_table(thd, first_table, &lex->check_opt); @@ -3035,7 +3114,7 @@ end_with_restore_list: { DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - UINT_MAX, FALSE)) + FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_analyze_table(thd, first_table, &lex->check_opt); @@ -3056,7 +3135,7 @@ end_with_restore_list: { DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - UINT_MAX, FALSE)) + FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? @@ -3429,7 +3508,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (!lex->drop_temporary) { - if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE)) + if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ if (end_active_trans(thd)) goto error; @@ -3474,9 +3553,6 @@ end_with_restore_list: case SQLCOM_SHOW_PRIVILEGES: res= mysqld_show_privileges(thd); break; - case SQLCOM_SHOW_COLUMN_TYPES: - res= mysqld_show_column_types(thd); - break; case SQLCOM_SHOW_ENGINE_LOGS: #ifdef DONT_ALLOW_SHOW_COMMANDS my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), @@ -3537,8 +3613,8 @@ end_with_restore_list: if (lex->autocommit && end_active_trans(thd)) goto error; - if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables))) + if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) + || open_and_lock_tables(thd, all_tables))) goto error; if (lex->one_shot_set && not_all_support_one_shot(lex_var_list)) { @@ -3592,7 +3668,7 @@ end_with_restore_list: if (end_active_trans(thd)) goto error; if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, - UINT_MAX, FALSE)) + FALSE, UINT_MAX, FALSE)) goto error; if (lex->protect_against_global_read_lock && !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1))) @@ -3988,7 +4064,7 @@ end_with_restore_list: else { if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL), - all_tables, 0, UINT_MAX, 0)) + all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog */ res= mysql_table_grant(thd, all_tables, lex->users_list, @@ -4097,7 +4173,7 @@ end_with_restore_list: #endif case SQLCOM_HA_OPEN: DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; res= mysql_ha_open(thd, first_table, 0); break; @@ -4383,7 +4459,8 @@ create_sp_error: This will cache all SP and SF and open and lock all tables required for execution. */ - if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || + if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, + UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables)) goto error; @@ -4453,12 +4530,6 @@ create_sp_error: So just execute the statement. */ res= sp->execute_procedure(thd, &lex->value_list); - /* - If warnings have been cleared, we have to clear total_warn_count - too, otherwise the clients get confused. - */ - if (thd->warn_list.is_empty()) - thd->total_warn_count= 0; thd->variables.select_limit= select_limit; @@ -4489,7 +4560,7 @@ create_sp_error: else sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname, &thd->sp_func_cache, FALSE); - mysql_reset_errors(thd, 0); + thd->warning_info->opt_clear_warning_info(thd->query_id); if (! sp) { if (lex->spname->m_db.str) @@ -4564,7 +4635,7 @@ create_sp_error: TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); sp_result= sp_routine_exists_in_table(thd, type, lex->spname); - mysql_reset_errors(thd, 0); + thd->warning_info->opt_clear_warning_info(thd->query_id); if (sp_result == SP_OK) { char *db= lex->spname->m_db.str; @@ -4668,10 +4739,10 @@ create_sp_error: } break; } -#ifndef DBUG_OFF case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_FUNC_CODE: { +#ifndef DBUG_OFF sp_head *sp; if (lex->sql_command == SQLCOM_SHOW_PROC_CODE) @@ -4688,8 +4759,12 @@ create_sp_error: goto error; } break; - } +#else + my_error(ER_FEATURE_DISABLED, MYF(0), + "SHOW PROCEDURE|FUNCTION CODE", "--with-debug"); + goto error; #endif // ifndef DBUG_OFF + } case SQLCOM_SHOW_CREATE_TRIGGER: { if (lex->spname->m_name.length > NAME_LEN) @@ -4717,8 +4792,8 @@ create_sp_error: } case SQLCOM_DROP_VIEW: { - if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) || - end_active_trans(thd)) + if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE) + || end_active_trans(thd)) goto error; /* Conditionally writes to binlog. */ res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); @@ -4928,7 +5003,7 @@ create_sp_error: res= mysql_xa_recover(thd); break; case SQLCOM_ALTER_TABLESPACE: - if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0)) + if (check_global_access(thd, CREATE_TABLESPACE_ACL)) break; if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info))) my_ok(thd); @@ -5015,6 +5090,11 @@ create_sp_error: my_ok(thd, 1); break; } + case SQLCOM_SIGNAL: + case SQLCOM_RESIGNAL: + DBUG_ASSERT(lex->m_stmt != NULL); + res= lex->m_stmt->execute(thd); + break; default: #ifndef EMBEDDED_LIBRARY DBUG_ASSERT(0); /* Impossible */ @@ -5160,7 +5240,7 @@ bool check_single_table_access(THD *thd, ulong privilege, /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && - check_grant(thd, privilege, all_tables, 0, 1, no_errors)) + check_grant(thd, privilege, all_tables, FALSE, 1, no_errors)) goto deny; thd->security_ctx= backup_ctx; @@ -5205,7 +5285,8 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) subselects_tables= subselects_tables->next_global; } if (subselects_tables && - (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE))) + (check_table_access(thd, SELECT_ACL, subselects_tables, FALSE, + UINT_MAX, FALSE))) return 1; } return 0; @@ -5213,46 +5294,54 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) /** - Get the user (global) and database privileges for all used tables. - - @param save_priv In this we store global and db level grants for the - table. Note that we don't store db level grants if the - global grants is enough to satisfy the request and the - global grants contains a SELECT grant. - - @note - The idea of EXTRA_ACL is that one will be granted access to the table if - one has the asked privilege on any column combination of the table; For - example to be able to check a table one needs to have SELECT privilege on - any column of the table. - - @retval - 0 ok - @retval - 1 If we can't get the privileges and we don't use table/column - grants. + @brief Compare requested privileges with the privileges acquired from the + User- and Db-tables. + @param thd Thread handler + @param want_access The requested access privileges. + @param db A pointer to the Db name. + @param[out] save_priv A pointer to the granted privileges will be stored. + @param dont_check_global_grants True if no global grants are checked. + @param no_error True if no errors should be sent to the client. + @param schema_db True if the db specified belongs to the meta data tables. + + 'save_priv' is used to save the User-table (global) and Db-table grants for + the supplied db name. Note that we don't store db level grants if the global + grants is enough to satisfy the request AND the global grants contains a + SELECT grant. + + A meta data table (from INFORMATION_SCHEMA) can always be accessed with + a SELECT_ACL. + + @see check_grant + + @return Status of denial of access by exclusive ACLs. + @retval FALSE Access can't exclusively be denied by Db- and User-table + access unless Column- and Table-grants are checked too. + @retval TRUE Access denied. */ + bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors, bool schema_db) { Security_context *sctx= thd->security_ctx; ulong db_access; + /* GRANT command: In case of database level grant the database name may be a pattern, in case of table|column level grant the database name can not be a pattern. We use 'dont_check_global_grants' as a flag to determine - if it's database level grant command + if it's database level grant command (see SQLCOM_GRANT case, mysql_execute_command() function) and set db_is_pattern according to 'dont_check_global_grants' value. */ - bool db_is_pattern= (test(want_access & GRANT_ACL) && - dont_check_global_grants); + bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants); ulong dummy; DBUG_ENTER("check_access"); DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu", db ? db : "", want_access, sctx->master_access)); + if (save_priv) *save_priv=0; else @@ -5270,8 +5359,12 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (schema_db) { - if ((!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL)) || - (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) + /* + We don't allow any simple privileges but SELECT_ACL or CREATE_VIEW_ACL + on the information_schema database. + */ + want_access &= ~SELECT_ACL; + if (want_access & DB_ACLS) { if (!no_errors) { @@ -5279,10 +5372,15 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, db_name); } + /* + Access denied; + [out] *save_privileges= 0 + */ DBUG_RETURN(TRUE); } else { + /* Access granted */ *save_priv= SELECT_ACL; DBUG_RETURN(FALSE); } @@ -5290,20 +5388,27 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((sctx->master_access & want_access) == want_access) { + /* get access for current db */ + db_access= sctx->db_access; /* - If we don't have a global SELECT privilege, we have to get the database - specific access rights to be able to handle queries of type + 1. If we don't have a global SELECT privilege, we have to get the + database specific access rights to be able to handle queries of type UPDATE t1 SET a=1 WHERE b > 0 + 2. Change db access if it isn't current db which is being addressed */ - db_access= sctx->db_access; if (!(sctx->master_access & SELECT_ACL) && (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))) db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db, db_is_pattern); + + /* + The effective privileges are the union of the global privileges + and the the intersection of db- and host-privileges. + */ *save_priv=sctx->master_access | db_access; DBUG_RETURN(FALSE); } - if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) || + if (((want_access & ~sctx->master_access) & ~DB_ACLS) || (! db && dont_check_global_grants)) { // We can never grant this DBUG_PRINT("error",("No possible access")); @@ -5318,33 +5423,66 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, } if (db == any_db) - DBUG_RETURN(FALSE); // Allow select on anything + { + /* + Access granted; Allow select on *any* db. + [out] *save_privileges= 0 + */ + DBUG_RETURN(FALSE); + } if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))) db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, db_is_pattern); else db_access= sctx->db_access; - DBUG_PRINT("info",("db_access: %lu", db_access)); - /* Remove SHOW attribute and access rights we already have */ - want_access &= ~(sctx->master_access | EXTRA_ACL); DBUG_PRINT("info",("db_access: %lu want_access: %lu", db_access, want_access)); - db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access); - if (db_access == want_access || + /* + Save the union of User-table and the intersection between Db-table and + Host-table privileges. + */ + db_access= (db_access | sctx->master_access); + *save_priv= db_access; + + /* + We need to investigate column- and table access if all requested privileges + belongs to the bit set of . + */ + bool need_table_or_column_check= + (want_access & (TABLE_ACLS | PROC_ACLS | db_access)) == want_access; + + /* + Grant access if the requested access is in the intersection of + host- and db-privileges (as retrieved from the acl cache), + also grant access if all the requested privileges are in the union of + TABLES_ACLS and PROC_ACLS; see check_grant. + */ + if ( (db_access & want_access) == want_access || (!dont_check_global_grants && - !(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS)))) - DBUG_RETURN(FALSE); /* Ok */ + need_table_or_column_check)) + { + /* + Ok; but need to check table- and column privileges. + [out] *save_privileges is (User-priv | (Db-priv & Host-priv)) + */ + DBUG_RETURN(FALSE); + } + /* + Access is denied; + [out] *save_privileges is (User-priv | (Db-priv & Host-priv)) + */ DBUG_PRINT("error",("Access denied")); if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, (db ? db : (thd->db ? thd->db : - "unknown"))); /* purecov: tested */ - DBUG_RETURN(TRUE); /* purecov: tested */ + "unknown"))); + DBUG_RETURN(TRUE); + } @@ -5390,14 +5528,20 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) DBUG_ASSERT(dst_table); - if (check_access(thd, SELECT_ACL | EXTRA_ACL, - dst_table->db, - &dst_table->grant.privilege, - FALSE, FALSE, + if (check_access(thd, SELECT_ACL, dst_table->db, + &dst_table->grant.privilege, FALSE, FALSE, test(dst_table->schema_table))) - return FALSE; + return TRUE; /* Access denied */ + + /* + Check_grant will grant access if there is any column privileges on + all of the tables thanks to the fourth parameter (bool show_table). + */ + if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE)) + return TRUE; /* Access denied */ - return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE)); + /* Access granted */ + return FALSE; } default: break; @@ -5407,30 +5551,46 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) } -/** - Check the privilege for all used tables. - @param thd Thread context - @param want_access Privileges requested - @param tables List of tables to be checked - @param number Check at most this number of tables. - @param no_errors FALSE/TRUE - report/don't report error to - the client (using my_error() call). +/** + @brief Check if the requested privileges exists in either User-, Host- or + Db-tables. + @param thd Thread context + @param want_access Privileges requested + @param tables List of tables to be compared against + @param no_errors Don't report error to the client (using my_error() call). + @param any_combination_of_privileges_will_do TRUE if any privileges on any + column combination is enough. + @param number Only the first 'number' tables in the linked list are + relevant. + + The suppled table list contains cached privileges. This functions calls the + help functions check_access and check_grant to verify the first three steps + in the privileges check queue: + 1. Global privileges + 2. OR (db privileges AND host privileges) + 3. OR table privileges + 4. OR column privileges (not checked by this function!) + 5. OR routine privileges (not checked by this function!) + + @see check_access + @see check_grant + + @note This functions assumes that table list used and + thd->lex->query_tables_own_last value correspond to each other + (the latter should be either 0 or point to next_global member + of one of elements of this table list). - @note - Table privileges are cached in the table list for GRANT checking. - This functions assumes that table list used and - thd->lex->query_tables_own_last value correspond to each other - (the latter should be either 0 or point to next_global member - of one of elements of this table list). - - @retval FALSE OK - @retval TRUE Access denied + @return + @retval FALSE OK + @retval TRUE Access denied; But column or routine privileges might need to + be checked also. */ bool -check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, - uint number, bool no_errors) +check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, + bool any_combination_of_privileges_will_do, + uint number, bool no_errors) { TABLE_LIST *org_tables= tables; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); @@ -5441,22 +5601,31 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, the given table list refers to the list for prelocking (contains tables of other queries). For simple queries first_not_own_table is 0. */ - for (; i < number && tables != first_not_own_table; + for (; i < number && tables != first_not_own_table && tables; tables= tables->next_global, i++) { + ulong want_access= requirements; if (tables->security_ctx) sctx= tables->security_ctx; else sctx= backup_ctx; - if (tables->schema_table && - (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) + /* + Always allow SELECT on schema tables. This is done by removing the + required SELECT_ACL privilege in the want_access parameter. + Disallow any other DDL or DML operation on any schema table. + */ + if (tables->schema_table) { - if (!no_errors) - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - sctx->priv_user, sctx->priv_host, - INFORMATION_SCHEMA_NAME.str); - return TRUE; + want_access &= ~SELECT_ACL; + if (want_access & DB_ACLS) + { + if (!no_errors) + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, sctx->priv_host, + INFORMATION_SCHEMA_NAME.str); + goto deny; + } } /* Register access for view underlying table. @@ -5468,33 +5637,34 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, { if (check_show_access(thd, tables)) goto deny; - continue; } + DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0, + tables->view != 0)); if (tables->is_anonymous_derived_table() || - (tables->table && (int)tables->table->s->tmp_table)) + (tables->table && tables->table->s && + (int)tables->table->s->tmp_table)) continue; thd->security_ctx= sctx; - if ((sctx->master_access & want_access) == - (want_access & ~EXTRA_ACL) && - thd->db) + if ((sctx->master_access & want_access) == want_access && + thd->db) tables->grant.privilege= want_access; else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0) { if (check_access(thd, want_access, tables->get_db_name(), - &tables->grant.privilege, 0, no_errors, + &tables->grant.privilege, 0, no_errors, test(tables->schema_table))) goto deny; // Access denied } else if (check_access(thd, want_access, tables->get_db_name(), - &tables->grant.privilege, 0, no_errors, - test(tables->schema_table))) + &tables->grant.privilege, 0, no_errors, 0)) goto deny; } thd->security_ctx= backup_ctx; - return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, - test(want_access & EXTRA_ACL), number, no_errors); + return check_grant(thd,requirements,org_tables, + any_combination_of_privileges_will_do, + number, no_errors); deny: thd->security_ctx= backup_ctx; return TRUE; @@ -5582,7 +5752,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) if (!check_access(thd, access, table->db, &table->grant.privilege, 0, 1, test(table->schema_table)) && - !check_grant(thd, access, table, 0, 1, 1)) + !check_grant(thd, access, table, FALSE, 1, TRUE)) DBUG_RETURN(0); } } @@ -5762,8 +5932,8 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->user_var_events_alloc= thd->mem_root; } thd->clear_error(); - thd->main_da.reset_diagnostics_area(); - thd->total_warn_count=0; // Warnings for this query + thd->stmt_da->reset_diagnostics_area(); + thd->warning_info->reset_for_next_command(); thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; @@ -6049,7 +6219,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, DBUG_PRINT("info",("Command aborted. Fatal_error: %d", thd->is_fatal_error)); - query_cache_abort(&thd->net); + query_cache_abort(&thd->query_cache_tls); } if (thd->lex->sphead) { @@ -6133,8 +6303,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, if (type_modifier & PRI_KEY_FLAG) { Key *key; - lex->col_list.push_back(new Key_part_spec(field_name->str, 0)); - key= new Key(Key::PRIMARY, NullS, + lex->col_list.push_back(new Key_part_spec(*field_name, 0)); + key= new Key(Key::PRIMARY, null_lex_str, &default_key_create_info, 0, lex->col_list); lex->alter_info.key_list.push_back(key); @@ -6143,8 +6313,8 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type, if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG)) { Key *key; - lex->col_list.push_back(new Key_part_spec(field_name->str, 0)); - key= new Key(Key::UNIQUE, NullS, + lex->col_list.push_back(new Key_part_spec(*field_name, 0)); + key= new Key(Key::UNIQUE, null_lex_str, &default_key_create_info, 0, lex->col_list); lex->alter_info.key_list.push_back(key); @@ -6344,7 +6514,19 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db, INFORMATION_SCHEMA_NAME.str)) { - ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name); + ST_SCHEMA_TABLE *schema_table; + if (ptr->updating && + /* Special cases which are processed by commands itself */ + lex->sql_command != SQLCOM_CHECK && + lex->sql_command != SQLCOM_CHECKSUM) + { + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->security_ctx->priv_user, + thd->security_ctx->priv_host, + INFORMATION_SCHEMA_NAME.str); + DBUG_RETURN(0); + } + schema_table= find_schema_table(thd, ptr->table_name); if (!schema_table || (schema_table->hidden && ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || @@ -7277,11 +7459,11 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) else if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege, 0, 1, test(table->schema_table)) || - check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && + check_grant(thd, UPDATE_ACL, table, FALSE, 1, TRUE)) && (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0, test(table->schema_table)) || - check_grant(thd, SELECT_ACL, table, 0, 1, 0))) + check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE))) DBUG_RETURN(TRUE); table->table_in_first_from_clause= 1; @@ -7299,7 +7481,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) if (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0, test(table->schema_table)) || - check_grant(thd, SELECT_ACL, table, 0, 1, 0)) + check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); } } @@ -7339,7 +7521,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); - if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) DBUG_RETURN(TRUE); /* @@ -7348,7 +7530,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) call check_table_access() safely. */ thd->lex->query_tables_own_last= 0; - if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE)) + if (check_table_access(thd, DELETE_ACL, aux_tables, FALSE, UINT_MAX, FALSE)) { thd->lex->query_tables_own_last= save_query_tables_own_last; DBUG_RETURN(TRUE); @@ -7502,25 +7684,6 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables) /** - @brief Check privileges for SHOW CREATE TABLE statement. - - @param thd Thread context - @param table Target table - - @retval TRUE Failure - @retval FALSE Success -*/ - -static bool check_show_create_table_access(THD *thd, TABLE_LIST *table) -{ - return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db, - &table->grant.privilege, 0, 0, - test(table->schema_table)) || - check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0); -} - - -/** CREATE TABLE query pre-check. @param thd Thread handler @@ -7559,7 +7722,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, lex->create_info.merge_list.first)) goto err; if (want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table, 0, 1, 0)) + check_grant(thd, want_priv, create_table, FALSE, 1, FALSE)) goto err; if (select_lex->item_list.elements) @@ -7587,12 +7750,13 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, } } #endif - if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) + if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE, + UINT_MAX, FALSE)) goto err; } else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE) { - if (check_show_create_table_access(thd, tables)) + if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) goto err; } error= FALSE; @@ -7790,7 +7954,10 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, return FALSE; if (!no_error) - my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length); + { + ErrConvString err(str->str, str->length, cs); + my_error(ER_WRONG_STRING_LENGTH, MYF(0), err.ptr(), err_msg, max_char_length); + } return TRUE; } |