diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 1552 |
1 files changed, 805 insertions, 747 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d6bbefc3be7..0e17370e93c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #define MYSQL_LEX 1 -#include <my_global.h> +#include "mariadb.h" #include "sql_priv.h" #include "sql_parse.h" // sql_kill, *_precheck, *_prepare #include "lock.h" // try_transactional_lock, @@ -82,7 +82,6 @@ #include <m_ctype.h> #include <myisam.h> #include <my_dir.h> -#include "rpl_handler.h" #include "rpl_mi.h" #include "sql_digest.h" @@ -99,8 +98,8 @@ #include "debug_sync.h" #include "probes_mysql.h" #include "set_var.h" -#include "log_slow.h" #include "sql_bootstrap.h" +#include "sql_sequence.h" #include "my_json_writer.h" @@ -123,14 +122,6 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, @{ */ -/* Used in error handling only */ -#define SP_COM_STRING(LP) \ - ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \ - (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \ - (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \ - (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ - "FUNCTION" : "PROCEDURE") - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); static void sql_kill(THD *thd, longlong id, killed_state state, killed_type type); static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state); @@ -140,39 +131,39 @@ static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); const char *any_db="*any*"; // Special symbol for check_access -const LEX_STRING command_name[257]={ - { C_STRING_WITH_LEN("Sleep") }, //0 - { C_STRING_WITH_LEN("Quit") }, //1 - { C_STRING_WITH_LEN("Init DB") }, //2 - { C_STRING_WITH_LEN("Query") }, //3 - { C_STRING_WITH_LEN("Field List") }, //4 - { C_STRING_WITH_LEN("Create DB") }, //5 - { C_STRING_WITH_LEN("Drop DB") }, //6 - { C_STRING_WITH_LEN("Refresh") }, //7 - { C_STRING_WITH_LEN("Shutdown") }, //8 - { C_STRING_WITH_LEN("Statistics") }, //9 - { C_STRING_WITH_LEN("Processlist") }, //10 - { C_STRING_WITH_LEN("Connect") }, //11 - { C_STRING_WITH_LEN("Kill") }, //12 - { C_STRING_WITH_LEN("Debug") }, //13 - { C_STRING_WITH_LEN("Ping") }, //14 - { C_STRING_WITH_LEN("Time") }, //15 - { C_STRING_WITH_LEN("Delayed insert") }, //16 - { C_STRING_WITH_LEN("Change user") }, //17 - { C_STRING_WITH_LEN("Binlog Dump") }, //18 - { C_STRING_WITH_LEN("Table Dump") }, //19 - { C_STRING_WITH_LEN("Connect Out") }, //20 - { C_STRING_WITH_LEN("Register Slave") }, //21 - { C_STRING_WITH_LEN("Prepare") }, //22 - { C_STRING_WITH_LEN("Execute") }, //23 - { C_STRING_WITH_LEN("Long Data") }, //24 - { C_STRING_WITH_LEN("Close stmt") }, //25 - { C_STRING_WITH_LEN("Reset stmt") }, //26 - { C_STRING_WITH_LEN("Set option") }, //27 - { C_STRING_WITH_LEN("Fetch") }, //28 - { C_STRING_WITH_LEN("Daemon") }, //29 - { C_STRING_WITH_LEN("Unimpl get tid") }, //30 - { C_STRING_WITH_LEN("Reset connection") },//31 +const LEX_CSTRING command_name[257]={ + { STRING_WITH_LEN("Sleep") }, //0 + { STRING_WITH_LEN("Quit") }, //1 + { STRING_WITH_LEN("Init DB") }, //2 + { STRING_WITH_LEN("Query") }, //3 + { STRING_WITH_LEN("Field List") }, //4 + { STRING_WITH_LEN("Create DB") }, //5 + { STRING_WITH_LEN("Drop DB") }, //6 + { STRING_WITH_LEN("Refresh") }, //7 + { STRING_WITH_LEN("Shutdown") }, //8 + { STRING_WITH_LEN("Statistics") }, //9 + { STRING_WITH_LEN("Processlist") }, //10 + { STRING_WITH_LEN("Connect") }, //11 + { STRING_WITH_LEN("Kill") }, //12 + { STRING_WITH_LEN("Debug") }, //13 + { STRING_WITH_LEN("Ping") }, //14 + { STRING_WITH_LEN("Time") }, //15 + { STRING_WITH_LEN("Delayed insert") }, //16 + { STRING_WITH_LEN("Change user") }, //17 + { STRING_WITH_LEN("Binlog Dump") }, //18 + { STRING_WITH_LEN("Table Dump") }, //19 + { STRING_WITH_LEN("Connect Out") }, //20 + { STRING_WITH_LEN("Register Slave") }, //21 + { STRING_WITH_LEN("Prepare") }, //22 + { STRING_WITH_LEN("Execute") }, //23 + { STRING_WITH_LEN("Long Data") }, //24 + { STRING_WITH_LEN("Close stmt") }, //25 + { STRING_WITH_LEN("Reset stmt") }, //26 + { STRING_WITH_LEN("Set option") }, //27 + { STRING_WITH_LEN("Fetch") }, //28 + { STRING_WITH_LEN("Daemon") }, //29 + { STRING_WITH_LEN("Unimpl get tid") }, //30 + { STRING_WITH_LEN("Reset connection") },//31 { 0, 0 }, //32 { 0, 0 }, //33 { 0, 0 }, //34 @@ -391,12 +382,12 @@ const LEX_STRING command_name[257]={ { 0, 0 }, //247 { 0, 0 }, //248 { 0, 0 }, //249 - { C_STRING_WITH_LEN("Bulk_execute") }, //250 - { C_STRING_WITH_LEN("Slave_worker") }, //251 - { C_STRING_WITH_LEN("Slave_IO") }, //252 - { C_STRING_WITH_LEN("Slave_SQL") }, //253 - { C_STRING_WITH_LEN("Com_multi") }, //254 - { C_STRING_WITH_LEN("Error") } // Last command number 255 + { STRING_WITH_LEN("Bulk_execute") }, //250 + { STRING_WITH_LEN("Slave_worker") }, //251 + { STRING_WITH_LEN("Slave_IO") }, //252 + { STRING_WITH_LEN("Slave_SQL") }, //253 + { STRING_WITH_LEN("Com_multi") }, //254 + { STRING_WITH_LEN("Error") } // Last command number 255 }; const char *xa_state_names[]={ @@ -411,7 +402,7 @@ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; return rpl_filter->is_on() && tables && !thd->spcont && - !rpl_filter->tables_ok(thd->db, tables); + !rpl_filter->tables_ok(thd->db.str, tables); } #endif @@ -420,7 +411,7 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) { for (TABLE_LIST *table= tables; table; table= table->next_global) { - DBUG_ASSERT(table->db && table->table_name); + DBUG_ASSERT(table->db.str && table->table_name.str); if (table->updating && !thd->find_tmp_table_share(table)) return 1; } @@ -448,14 +439,17 @@ bool stmt_causes_implicit_commit(THD *thd, uint mask) switch (lex->sql_command) { case SQLCOM_DROP_TABLE: + case SQLCOM_DROP_SEQUENCE: skip= (lex->tmp_table() || (thd->variables.option_bits & OPTION_GTID_BEGIN)); break; case SQLCOM_ALTER_TABLE: + case SQLCOM_ALTER_SEQUENCE: /* If ALTER TABLE of non-temporary table, do implicit commit */ skip= (lex->tmp_table()); break; case SQLCOM_CREATE_TABLE: + case SQLCOM_CREATE_SEQUENCE: /* If CREATE TABLE of non-temporary table and the table is not part if a BEGIN GTID ... COMMIT group, do a implicit commit. @@ -544,24 +538,36 @@ void init_update_queries(void) */ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | - CF_CAN_GENERATE_ROW_EVENTS; + CF_CAN_GENERATE_ROW_EVENTS | + CF_SCHEMA_CHANGE; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]= (CF_CHANGES_DATA | + CF_REEXECUTION_FRAGILE | + CF_AUTO_COMMIT_TRANS | + CF_SCHEMA_CHANGE); sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | - CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; + CF_ADMIN_COMMAND | CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_INSERTS_DATA | CF_ADMIN_COMMAND; + sql_command_flags[SQLCOM_ALTER_SEQUENCE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | + CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE | + CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; + sql_command_flags[SQLCOM_DROP_SEQUENCE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS | CF_INSERTS_DATA; - sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; + sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; + sql_command_flags[SQLCOM_CREATE_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | - CF_ADMIN_COMMAND; + sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; + sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | @@ -603,7 +609,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | - CF_CAN_BE_EXPLAINED;; + CF_CAN_BE_EXPLAINED; sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -635,6 +641,8 @@ void init_update_queries(void) CF_OPTIMIZER_TRACE; // (1) sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE_BODY]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; @@ -669,10 +677,13 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE_BODY]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_PACKAGE_BODY_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND; @@ -728,6 +739,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_TRUNCATE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* We don't want to replicate DROP for temp tables in row format */ sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; /* We don't want to replicate CREATE/DROP INDEX for temp tables in row format */ sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; sql_command_flags[SQLCOM_DROP_INDEX]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; @@ -809,7 +821,9 @@ void init_update_queries(void) have to be closed before temporary tables are pre-opened. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; @@ -827,13 +841,19 @@ void init_update_queries(void) even temporary table DDL should be disallowed. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS; @@ -928,7 +948,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, save_vio= thd->net.vio; thd->net.vio= 0; thd->clear_error(1); - dispatch_command(COM_QUERY, thd, buf, len, FALSE, FALSE); + dispatch_command(COM_QUERY, thd, buf, (uint)len, FALSE, FALSE); thd->client_capabilities= save_client_capabilities; thd->net.vio= save_vio; @@ -941,8 +961,8 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, static char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error) { MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input); - char *line= mysql_file_fgets(buffer, size, in); - if (error) + char *line= mysql_file_fgets(buffer, (int)size, in); + if (unlikely(error)) *error= (line == NULL) ? ferror(in->m_file) : 0; return line; } @@ -1020,7 +1040,7 @@ static void handle_bootstrap_impl(THD *thd) } query= (char *) thd->memdup_w_gap(buffer, length + 1, - thd->db_length + 1 + + thd->db.length + 1 + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE); size_t db_len= 0; @@ -1056,7 +1076,7 @@ static void handle_bootstrap_impl(THD *thd) #endif delete_explain_query(thd->lex); - if (bootstrap_error) + if (unlikely(bootstrap_error)) break; thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ @@ -1166,15 +1186,10 @@ static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables) for (const TABLE_LIST *table= tables; table; table= table->next_global) { TABLE_CATEGORY c; - LEX_STRING db, tn; - lex_string_set(&db, table->db); - lex_string_set(&tn, table->table_name); + LEX_CSTRING db= table->db, tn= table->table_name; c= get_table_category(&db, &tn); - if (c != TABLE_CATEGORY_INFORMATION && - c != TABLE_CATEGORY_PERFORMANCE) - { + if (c != TABLE_CATEGORY_INFORMATION && c != TABLE_CATEGORY_PERFORMANCE) return false; - } } return true; } @@ -1231,8 +1246,8 @@ bool do_command(THD *thd) the client, the connection is closed or "net_wait_timeout" number of seconds has passed. */ - if(!thd->skip_wait_timeout) - my_net_set_read_timeout(net, thd->variables.net_wait_timeout); + if (!thd->skip_wait_timeout) + my_net_set_read_timeout(net, thd->get_net_wait_timeout()); /* Errors and diagnostics are cleared once here before query */ thd->clear_error(1); @@ -1283,7 +1298,7 @@ bool do_command(THD *thd) } #endif /* WITH_WSREP */ - if (packet_length == packet_error) + if (unlikely(packet_length == packet_error)) { DBUG_PRINT("info",("Got error %d reading command from socket %s", net->error, @@ -1295,7 +1310,8 @@ bool do_command(THD *thd) mysql_mutex_lock(&thd->LOCK_thd_data); if (thd->wsrep_conflict_state == MUST_ABORT) { - DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id)); + DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", + (ulong) thd->real_id)); wsrep_client_rollback(thd); } mysql_mutex_unlock(&thd->LOCK_thd_data); @@ -1431,7 +1447,7 @@ out: This is a helper function to mysql_execute_command. - @note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere. + @note SQLCOM_MULTI_UPDATE is an exception and dealt with elsewhere. @see mysql_execute_command @returns Status code @@ -1448,9 +1464,12 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) LEX *lex= thd->lex; - if (thd->security_ctx->master_access & SUPER_ACL) + /* Super user is allowed to do changes */ + if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) == + (ulong)SUPER_ACL)) DBUG_RETURN(FALSE); + /* Check if command doesn't update anything */ if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA)) DBUG_RETURN(FALSE); @@ -1458,11 +1477,6 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) if (lex->sql_command == SQLCOM_UPDATE_MULTI) DBUG_RETURN(FALSE); - if (lex->sql_command == SQLCOM_CREATE_DB || - lex->sql_command == SQLCOM_ALTER_DB || - lex->sql_command == SQLCOM_DROP_DB) - DBUG_RETURN(TRUE); - /* a table-to-be-created is not in the temp table list yet, so CREATE TABLE needs a special treatment @@ -1477,8 +1491,15 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) if (lex->sql_command == SQLCOM_DROP_TABLE && lex->tmp_table()) DBUG_RETURN(FALSE); - /* Now, check thd->temporary_tables list */ - DBUG_RETURN(some_non_temp_table_to_be_updated(thd, all_tables)); + /* Check if we created, dropped, or renamed a database */ + if ((sql_command_flags[lex->sql_command] & CF_DB_CHANGE)) + DBUG_RETURN(TRUE); + + if (some_non_temp_table_to_be_updated(thd, all_tables)) + DBUG_RETURN(TRUE); + + /* Assuming that only temporary tables are modified. */ + DBUG_RETURN(FALSE); } @@ -1493,7 +1514,7 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) @retval # - Number of commands in the batch */ -uint maria_multi_check(THD *thd, char *packet, uint packet_length) +uint maria_multi_check(THD *thd, char *packet, size_t packet_length) { uint counter= 0; DBUG_ENTER("maria_multi_check"); @@ -1560,9 +1581,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, "<?>"))); bool drop_more_results= 0; - if (!is_com_multi) - inc_thread_running(); - /* keep it withing 1 byte */ compile_time_assert(COM_END == 255); @@ -1610,12 +1628,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_EXECUTE_IF("crash_dispatch_command_before", { DBUG_PRINT("crash_dispatch_command_before", ("now")); - DBUG_ABORT(); }); + DBUG_SUICIDE(); }); /* Performance Schema Interface instrumentation, begin */ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, com_statement_info[command]. m_key); + /* + We should always call reset_for_next_command() before a query. + mysql_parse() will do this for queries. Ensure it's also done + for other commands. + */ + if (command != COM_QUERY) + thd->reset_for_next_command(); thd->set_command(command); thd->enable_slow_log= true; @@ -1665,14 +1690,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, switch (command) { case COM_INIT_DB: { - LEX_STRING tmp; + LEX_CSTRING tmp; status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]); - if (thd->copy_with_error(system_charset_info, &tmp, - thd->charset(), packet, packet_length)) + if (unlikely(thd->copy_with_error(system_charset_info, (LEX_STRING*) &tmp, + thd->charset(), packet, packet_length))) break; if (!mysql_change_db(thd, &tmp, FALSE)) { - general_log_write(thd, command, thd->db, thd->db_length); + general_log_write(thd, command, thd->db.str, thd->db.length); my_ok(thd); } break; @@ -1708,8 +1733,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* acl_authenticate() takes the data from net->read_pos */ net->read_pos= (uchar*)packet; - uint save_db_length= thd->db_length; - char *save_db= thd->db; + LEX_CSTRING save_db= thd->db; USER_CONN *save_user_connect= thd->user_connect; Security_context save_security_ctx= *thd->security_ctx; CHARSET_INFO *save_character_set_client= @@ -1740,12 +1764,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (auth_rc) { /* Free user if allocated by acl_authenticate */ - my_free(thd->security_ctx->user); + my_free(const_cast<char*>(thd->security_ctx->user)); *thd->security_ctx= save_security_ctx; if (thd->user_connect) decrease_user_connections(thd->user_connect); thd->user_connect= save_user_connect; - thd->reset_db(save_db, save_db_length); + thd->reset_db(&save_db); thd->update_charset(save_character_set_client, save_collation_connection, save_character_set_results); thd->failed_com_change_user++; @@ -1758,8 +1782,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (save_user_connect) decrease_user_connections(save_user_connect); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - my_free(save_db); - my_free(save_security_ctx.user); + my_free((char*) save_db.str); + my_free(const_cast<char*>(save_security_ctx.user)); } break; } @@ -1804,10 +1828,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->m_digest= & thd->m_digest_state; thd->m_digest->reset(thd->m_token_array, max_digest_length); - if (alloc_query(thd, packet, packet_length)) + if (unlikely(alloc_query(thd, packet, packet_length))) break; // fatal error is set MYSQL_QUERY_START(thd->query(), thd->thread_id, - (char *) (thd->db ? thd->db : ""), + thd->get_db(), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip); char *packet_end= thd->query() + thd->query_length(); @@ -1820,7 +1844,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->query_length()); Parser_state parser_state; - if (parser_state.init(thd, thd->query(), thd->query_length())) + if (unlikely(parser_state.init(thd, thd->query(), thd->query_length()))) break; if (WSREP_ON) @@ -1885,7 +1909,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* DTRACE begin */ MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id, - (char *) (thd->db ? thd->db : ""), + thd->get_db(), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip); @@ -1894,7 +1918,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, com_statement_info[command].m_key, - thd->db, thd->db_length, + thd->db.str, thd->db.length, thd->charset()); THD_STAGE_INFO(thd, stage_init); MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt, @@ -1902,6 +1926,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_query_and_id(beginning_of_next_stmt, length, thd->charset(), next_query_id()); + /* Count each statement from the client. */ @@ -1911,7 +1936,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_time(); /* Reset the query start time. */ parser_state.reset(beginning_of_next_stmt, length); - /* TODO: set thd->lex->sql_command to SQLCOM_END here */ if (WSREP_ON) wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, @@ -1936,7 +1960,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Locked closure of all tables */ TABLE_LIST table_list; LEX_STRING table_name; - LEX_STRING db; + LEX_CSTRING db; /* SHOW statements should not add the used tables to the list of tables used in a transaction. @@ -1944,7 +1968,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]); - if (thd->copy_db_to(&db.str, &db.length)) + if (thd->copy_db_to(&db)) break; /* We have name + wildcard in packet, separated by endzero @@ -1969,7 +1993,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } packet= arg_end + 1; - thd->reset_for_next_command(0); // Don't clear errors // thd->reset_for_next_command reset state => restore it if (is_next_command) { @@ -1983,10 +2006,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (lower_case_table_names) { table_name.length= my_casedn_str(files_charset_info, table_name.str); - db.length= my_casedn_str(files_charset_info, db.str); + db.length= my_casedn_str(files_charset_info, (char*) db.str); } - table_list.init_one_table(db.str, db.length, table_name.str, - table_name.length, table_name.str, TL_READ); + table_list.init_one_table(&db, (LEX_CSTRING*) &table_name, 0, TL_READ); /* Init TABLE_LIST members necessary when the undelrying table is view. @@ -1997,9 +2019,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, &table_list.next_local); thd->lex->add_to_query_tables(&table_list); - if (is_infoschema_db(table_list.db, table_list.db_length)) + if (is_infoschema_db(&table_list.db)) { - ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias); + ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, &table_list.alias); if (schema_table) table_list.schema_table= schema_table; } @@ -2008,7 +2030,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (!(fields= (char *) thd->memdup(packet, query_length + 1))) break; thd->set_query(fields, query_length); - general_log_print(thd, command, "%s %s", table_list.table_name, fields); + general_log_print(thd, command, "%s %s", table_list.table_name.str, + fields); if (thd->open_temporary_tables(&table_list)) break; @@ -2129,7 +2152,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else #endif { - thd->lex->relay_log_connection_name= empty_lex_str; + thd->lex->relay_log_connection_name= empty_clex_str; if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) break; } @@ -2173,7 +2196,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { STATUS_VAR *current_global_status_var; // Big; Don't allocate on stack ulong uptime; - uint length __attribute__((unused)); ulonglong queries_per_second1000; char buff[250]; uint buff_len= sizeof(buff); @@ -2188,8 +2210,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, queries_per_second1000= 0; else queries_per_second1000= thd->query_id * 1000 / uptime; - - length= my_snprintf(buff, buff_len - 1, +#ifndef EMBEDDED_LIBRARY + size_t length= +#endif + my_snprintf(buff, buff_len - 1, "Uptime: %lu Threads: %d Questions: %lu " "Slow queries: %lu Opens: %lu Flush tables: %lld " "Open tables: %u Queries per second avg: %u.%03u", @@ -2316,7 +2340,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } if (dispatch_command(subcommand, thd, packet + (1 + length_length), - subpacket_length - (1 + length_length), TRUE, + (uint)(subpacket_length - (1 + length_length)), TRUE, (current_com != counter))) { DBUG_ASSERT(thd->is_error()); @@ -2325,7 +2349,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_ASSERT(subpacket_length <= packet_length); packet+= subpacket_length; - packet_length-= subpacket_length; + packet_length-= (uint)subpacket_length; } com_multi_end: @@ -2380,7 +2404,7 @@ com_multi_end: (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); - thd_proc_info(thd, "updating status"); + thd_proc_info(thd, "Updating status"); /* Finalize server status flags after executing a command. */ thd->update_server_status(); if (command != COM_MULTI) @@ -2392,7 +2416,7 @@ com_multi_end: if (drop_more_results) thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - if (!thd->is_error() && !thd->killed_errno()) + if (likely(!thd->is_error() && !thd->killed_errno())) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS, @@ -2416,10 +2440,8 @@ com_multi_end: thd->m_digest= NULL; if (!is_com_multi) - { - dec_thread_running(); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory - } + thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ /* LEX::m_sql_cmd can point to Sql_cmd allocated on thd->mem_root. @@ -2449,11 +2471,18 @@ com_multi_end: DBUG_RETURN(error); } +static bool slow_filter_masked(THD *thd, ulonglong mask) +{ + return thd->variables.log_slow_filter && !(thd->variables.log_slow_filter & mask); +} /* + Log query to slow queries, if it passes filtering + @note This function must call delete_explain_query(). */ + void log_slow_statement(THD *thd) { DBUG_ENTER("log_slow_statement"); @@ -2465,7 +2494,6 @@ void log_slow_statement(THD *thd) */ if (unlikely(thd->in_sub_stmt)) goto end; // Don't set time for sub stmt - /* Skip both long_query_count increment and logging if the current statement forces slow log suppression (e.g. an SP statement). @@ -2484,21 +2512,27 @@ void log_slow_statement(THD *thd) thd->server_status|= SERVER_QUERY_WAS_SLOW; }); - if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || - ((thd->server_status & - (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && - opt_log_queries_not_using_indexes && - !(thd->query_plan_flags & QPLAN_STATUS))) && + if ((thd->server_status & + (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && + !(thd->query_plan_flags & QPLAN_STATUS) && + !slow_filter_masked(thd, QPLAN_NOT_USING_INDEX)) + { + thd->query_plan_flags|= QPLAN_NOT_USING_INDEX; + /* We are always logging no index queries if enabled in filter */ + thd->server_status|= SERVER_QUERY_WAS_SLOW; + } + + if ((thd->server_status & SERVER_QUERY_WAS_SLOW) && thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; /* - until opt_log_slow_admin_statements is removed, it + until log_slow_disabled_statements=admin is removed, it duplicates slow_log_filter=admin */ if ((thd->query_plan_flags & QPLAN_ADMIN) && - !opt_log_slow_admin_statements) + (thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_ADMIN)) goto end; if (!global_system_variables.sql_log_slow || !thd->variables.sql_log_slow) @@ -2516,8 +2550,7 @@ void log_slow_statement(THD *thd) Follow the slow log filter configuration: skip logging if the current statement matches the filter. */ - if (thd->variables.log_slow_filter && - !(thd->variables.log_slow_filter & thd->query_plan_flags)) + if (slow_filter_masked(thd, thd->query_plan_flags)) goto end; THD_STAGE_INFO(thd, stage_logging_slow_query); @@ -2575,6 +2608,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, case SCH_TABLE_NAMES: case SCH_TABLES: + case SCH_CHECK_CONSTRAINTS: case SCH_VIEWS: case SCH_TRIGGERS: case SCH_EVENTS: @@ -2584,21 +2618,23 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); #else { - LEX_STRING db; - size_t dummy; - if (lex->select_lex.db == NULL && - lex->copy_db_to(&lex->select_lex.db, &dummy)) + if (lex->select_lex.db.str == NULL && + lex->copy_db_to(&lex->select_lex.db)) { DBUG_RETURN(1); } schema_select_lex= new (thd->mem_root) SELECT_LEX(); - db.str= schema_select_lex->db= lex->select_lex.db; schema_select_lex->table_list.first= NULL; - db.length= strlen(db.str); - - if (check_db_name(&db)) + if (lower_case_table_names == 1) + lex->select_lex.db.str= thd->strdup(lex->select_lex.db.str); + schema_select_lex->db= lex->select_lex.db; + /* + check_db_name() may change db.str if lower_case_table_names == 1, + but that's ok as the db is allocted above in this case. + */ + if (check_db_name((LEX_STRING*) &lex->select_lex.db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), db.str); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->select_lex.db.str); DBUG_RETURN(1); } break; @@ -2661,7 +2697,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, TRUE error; In this case thd->fatal_error is set */ -bool alloc_query(THD *thd, const char *packet, uint packet_length) +bool alloc_query(THD *thd, const char *packet, size_t packet_length) { char *query; /* Remove garbage at start and end of query */ @@ -2689,7 +2725,7 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) */ if (! (query= (char*) thd->memdup_w_gap(packet, packet_length, - 1 + thd->db_length + + 1 + thd->db.length + QUERY_CACHE_DB_LENGTH_SIZE + QUERY_CACHE_FLAGS_SIZE))) return TRUE; @@ -2699,7 +2735,7 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) also store this length, in case current database is changed during execution. We might need to reallocate the 'query' buffer */ - int2store(query + packet_length + 1, thd->db_length); + int2store(query + packet_length + 1, thd->db.length); thd->set_query(query, packet_length); @@ -2757,7 +2793,7 @@ bool sp_process_definer(THD *thd) DBUG_RETURN(TRUE); if (thd->slave_thread && lex->sphead) - lex->sphead->m_chistics->suid= SP_IS_NOT_SUID; + lex->sphead->set_suid(SP_IS_NOT_SUID); } else { @@ -2917,12 +2953,13 @@ static bool do_execute_sp(THD *thd, sp_head *sp) { /* bits that should be cleared in thd->server_status */ uint bits_to_be_cleared= 0; + ulonglong affected_rows; if (sp->m_flags & sp_head::MULTI_RESULTS) { if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) { /* The client does not support multiple result sets being sent back */ - my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); + my_error(ER_SP_BADSELECT, MYF(0), ErrConvDQName(sp).ptr()); return 1; } } @@ -2962,11 +2999,249 @@ static bool do_execute_sp(THD *thd, sp_head *sp) return 1; // Substatement should already have sent error } - my_ok(thd, (thd->get_row_count_func() < 0) ? 0 : thd->get_row_count_func()); + affected_rows= thd->affected_rows; // Affected rows for all sub statements + thd->affected_rows= 0; // Reset total, as my_ok() adds to it + my_ok(thd, affected_rows); return 0; } +static int mysql_create_routine(THD *thd, LEX *lex) +{ + DBUG_ASSERT(lex->sphead != 0); + DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ + /* + Verify that the database name is allowed, optionally + lowercase it. + */ + if (check_db_name((LEX_STRING*) &lex->sphead->m_db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); + return true; + } + + if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, + NULL, NULL, 0, 0)) + return true; + + /* Checking the drop permissions if CREATE OR REPLACE is used */ + if (lex->create_info.or_replace()) + { + if (check_routine_access(thd, ALTER_PROC_ACL, &lex->sphead->m_db, + &lex->sphead->m_name, + Sp_handler::handler(lex->sql_command), 0)) + return true; + } + + const LEX_CSTRING *name= lex->sphead->name(); +#ifdef HAVE_DLOPEN + if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION) + { + udf_func *udf = find_udf(name->str, name->length); + + if (udf) + { + my_error(ER_UDF_EXISTS, MYF(0), name->str); + return true; + } + } +#endif + + if (sp_process_definer(thd)) + return true; + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead)) + { +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* only add privileges if really neccessary */ + + Security_context security_context; + bool restore_backup_context= false; + Security_context *backup= NULL; + LEX_USER *definer= thd->lex->definer; + /* + We're going to issue an implicit GRANT statement so we close all + open tables. We have to keep metadata locks as this ensures that + this statement is atomic against concurent FLUSH TABLES WITH READ + LOCK. Deadlocks which can arise due to fact that this implicit + statement takes metadata locks should be detected by a deadlock + detector in MDL subsystem and reported as errors. + + No need to commit/rollback statement transaction, it's not started. + + TODO: Long-term we should either ensure that implicit GRANT statement + is written into binary log as a separate statement or make both + creation of routine and implicit GRANT parts of one fully atomic + statement. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + /* + Check if the definer exists on slave, + then use definer privilege to insert routine privileges to mysql.procs_priv. + + For current user of SQL thread has GLOBAL_ACL privilege, + which doesn't any check routine privileges, + so no routine privilege record will insert into mysql.procs_priv. + */ + if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str)) + { + security_context.change_security_context(thd, + &thd->lex->definer->user, + &thd->lex->definer->host, + &thd->lex->sphead->m_db, + &backup); + restore_backup_context= true; + } + + if (sp_automatic_privileges && !opt_noacl && + check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, + &lex->sphead->m_db, name, + Sp_handler::handler(lex->sql_command), 1)) + { + if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str, + Sp_handler::handler(lex->sql_command))) + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, + ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL)); + thd->clear_error(); + } + + /* + Restore current user with GLOBAL_ACL privilege of SQL thread + */ + if (restore_backup_context) + { + DBUG_ASSERT(thd->slave_thread == 1); + thd->security_ctx->restore_security_context(thd, backup); + } + +#endif + return false; + } +WSREP_ERROR_LABEL: + return true; +} + + +/** + Prepare for CREATE DATABASE, ALTER DATABASE, DROP DATABASE. + + @param thd - current THD + @param want_access - access needed + @param dbname - the database name + + @retval false - Ok to proceed with CREATE/ALTER/DROP + @retval true - not OK to proceed (error, or filtered) + + Note, on slave this function returns true if the database + is in the ignore filter. The caller must distinguish this case + from other cases: bad database error, no access error. + This can be done by testing thd->is_error(). +*/ +static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname) +{ + if (check_db_name((LEX_STRING*)dbname)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), dbname->str); + return true; + } + /* + If in a slave thread : + - CREATE DATABASE DB was certainly not preceded by USE DB. + - ALTER DATABASE DB may not be preceded by USE DB. + - DROP DATABASE DB may not be preceded by USE DB. + For that reason, db_ok() in sql/slave.cc did not check the + do_db/ignore_db. And as this query involves no tables, tables_ok() + was not called. So we have to check rules again here. + */ +#ifdef HAVE_REPLICATION + if (thd->slave_thread) + { + Rpl_filter *rpl_filter; + rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; + if (!rpl_filter->db_ok(dbname->str) || + !rpl_filter->db_ok_with_wild_table(dbname->str)) + { + my_message(ER_SLAVE_IGNORED_TABLE, + ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); + return true; + } + } +#endif + return check_access(thd, want_access, dbname->str, NULL, NULL, 1, 0); +} + + +bool Sql_cmd_call::execute(THD *thd) +{ + TABLE_LIST *all_tables= thd->lex->query_tables; + sp_head *sp; + /* + 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, FALSE, + UINT_MAX, FALSE) || + open_and_lock_tables(thd, all_tables, TRUE, 0)) + return true; + + /* + By this moment all needed SPs should be in cache so no need to look + into DB. + */ + if (!(sp= m_handler->sp_find_routine(thd, m_name, true))) + { + /* + If the routine is not found, let's still check EXECUTE_ACL to decide + whether to return "Access denied" or "Routine does not exist". + */ + if (check_routine_access(thd, EXECUTE_ACL, &m_name->m_db, + &m_name->m_name, + &sp_handler_procedure, + false)) + return true; + /* + sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. + Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in + cache. + */ + if (!sp_cache_lookup(&thd->sp_proc_cache, m_name)) + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", + ErrConvDQName(m_name).ptr()); + return true; + } + else + { + if (sp->check_execute_access(thd)) + return true; + /* + Check that the stored procedure doesn't contain Dynamic SQL + and doesn't return result sets: such stored procedures can't + be called from a function or trigger. + */ + if (thd->in_sub_stmt) + { + const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? + "trigger" : "function"); + if (sp->is_not_allowed_in_function(where)) + return true; + } + + if (do_execute_sp(thd, sp)) + return true; + + /* + Disable slow log for the above call(), if calls are disabled. + Instead we will log the executed statements to the slow log. + */ + if (thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_CALL) + thd->enable_slow_log= 0; + } + return false; +} + + /** Execute command saved in thd and lex->sql_command. @@ -3039,6 +3314,12 @@ mysql_execute_command(THD *thd) table_list.first); /* + Remember last commmand executed, so that we can use it in functions called by + dispatch_command() + */ + thd->last_sql_command= lex->sql_command; + + /* Reset warning count for each query that uses tables A better approach would be to reset this for any commands that is not a SHOW command or a select that only access local @@ -3139,7 +3420,8 @@ mysql_execute_command(THD *thd) */ if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && !(lex->sql_command == SQLCOM_SET_OPTION) && - !(lex->sql_command == SQLCOM_DROP_TABLE && + !((lex->sql_command == SQLCOM_DROP_TABLE || + lex->sql_command == SQLCOM_DROP_SEQUENCE) && lex->tmp_table() && lex->if_exists()) && all_tables_not_ok(thd, all_tables)) { @@ -3296,6 +3578,7 @@ mysql_execute_command(THD *thd) case GET_NO_ARG: case GET_DISABLED: DBUG_ASSERT(0); + /* fall through */ case 0: case GET_FLAGSET: case GET_ENUM: @@ -3474,8 +3757,7 @@ mysql_execute_command(THD *thd) Item **it= lex->value_list.head_ref(); if (!(*it)->basic_const_item() || - (!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || - (*it)->check_cols(1)) + (*it)->fix_fields_if_needed_for_scalar(lex->thd, it)) { my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -3485,6 +3767,8 @@ mysql_execute_command(THD *thd) /* fall through */ case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: + case SQLCOM_SHOW_STATUS_PACKAGE: + case SQLCOM_SHOW_STATUS_PACKAGE_BODY: case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TRIGGERS: @@ -3586,8 +3870,7 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || - it->check_cols(1)) + if (it->fix_fields_if_needed_for_scalar(lex->thd, &it)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); goto error; @@ -3649,7 +3932,7 @@ mysql_execute_command(THD *thd) case SQLCOM_ASSIGN_TO_KEYCACHE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_access(thd, INDEX_ACL, first_table->db, + if (check_access(thd, INDEX_ACL, first_table->db.str, &first_table->grant.privilege, &first_table->grant.m_internal, 0, 0)) @@ -3660,7 +3943,7 @@ mysql_execute_command(THD *thd) case SQLCOM_PRELOAD_KEYS: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_access(thd, INDEX_ACL, first_table->db, + if (check_access(thd, INDEX_ACL, first_table->db.str, &first_table->grant.privilege, &first_table->grant.m_internal, 0, 0)) @@ -3697,7 +3980,7 @@ mysql_execute_command(THD *thd) { /* New replication created */ mi= new Master_info(&lex_mi->connection_name, relay_log_recovery); - if (!mi || mi->error()) + if (unlikely(!mi || mi->error())) { delete mi; res= 1; @@ -3794,20 +4077,20 @@ mysql_execute_command(THD *thd) HA_CREATE_INFO create_info; Alter_info alter_info(lex->alter_info, thd->mem_root); - if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */ + if (unlikely(thd->is_fatal_error)) /* out of memory creating alter_info */ goto error; DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ - WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) + WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); bzero((char*) &create_info, sizeof(create_info)); create_info.db_type= 0; create_info.row_type= ROW_TYPE_NOT_USED; create_info.default_table_charset= thd->variables.collation_database; - res= mysql_alter_table(thd, first_table->db, first_table->table_name, + res= mysql_alter_table(thd, &first_table->db, &first_table->table_name, &create_info, first_table, &alter_info, 0, (ORDER*) 0, 0); break; @@ -3825,8 +4108,8 @@ mysql_execute_command(THD *thd) We don't need to ensure that only one user is using master_info as start_slave is protected against simultaneous usage */ - if ((mi= get_master_info(&lex_mi->connection_name, - Sql_condition::WARN_LEVEL_ERROR))) + if (unlikely((mi= get_master_info(&lex_mi->connection_name, + Sql_condition::WARN_LEVEL_ERROR)))) { if (load_error) { @@ -3919,7 +4202,7 @@ mysql_execute_command(THD *thd) if (check_rename_table(thd, first_table, all_tables)) goto error; - WSREP_TO_ISOLATION_BEGIN(0, 0, first_table) + WSREP_TO_ISOLATION_BEGIN(0, 0, first_table); if (mysql_rename_tables(thd, first_table, 0)) goto error; @@ -3961,8 +4244,8 @@ mysql_execute_command(THD *thd) */ DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s", - lex->only_view, - first_table->db, first_table->table_name)); + lex->table_type == TABLE_TYPE_VIEW, + first_table->db.str, first_table->table_name.str)); res= mysqld_show_create(thd, first_table); break; #endif @@ -4010,8 +4293,7 @@ mysql_execute_command(THD *thd) select_lex->order_list.elements, select_lex->order_list.first, unit->select_limit_cnt, - lex->duplicates, lex->ignore, - &found, &updated); + lex->ignore, &found, &updated); MYSQL_UPDATE_DONE(res, found, updated); /* mysql_update return 2 if we need to switch to multi-update */ if (up_result != 2) @@ -4031,6 +4313,7 @@ mysql_execute_command(THD *thd) else res= 0; + unit->set_limit(select_lex); /* We can not use mysql_explain_union() because of parameters of mysql_select in mysql_multi_update so just set the option if needed @@ -4214,7 +4497,7 @@ mysql_execute_command(THD *thd) if (WSREP(thd) && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) { thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; - WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL); + WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); } #endif /* WITH_WSREP */ @@ -4343,7 +4626,7 @@ mysql_execute_command(THD *thd) unit->set_limit(select_lex); MYSQL_DELETE_START(thd->query()); - Protocol *save_protocol; + Protocol * UNINIT_VAR(save_protocol); bool replaced_protocol= false; if (!select_lex->item_list.is_empty()) @@ -4412,17 +4695,17 @@ mysql_execute_command(THD *thd) break; MYSQL_MULTI_DELETE_START(thd->query()); - if ((res= mysql_multi_delete_prepare(thd))) + if (unlikely(res= mysql_multi_delete_prepare(thd))) { MYSQL_MULTI_DELETE_DONE(1, 0); goto error; } - if (!thd->is_fatal_error) + if (likely(!thd->is_fatal_error)) { result= new (thd->mem_root) multi_delete(thd, aux_tables, lex->table_count); - if (result) + if (unlikely(result)) { res= mysql_select(thd, select_lex->get_table_list(), @@ -4435,7 +4718,7 @@ mysql_execute_command(THD *thd) SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, result, unit, select_lex); - res|= thd->is_error(); + res|= (int)(thd->is_error()); MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); if (res) @@ -4455,6 +4738,7 @@ mysql_execute_command(THD *thd) } break; } + case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { int result; @@ -4472,7 +4756,7 @@ mysql_execute_command(THD *thd) } else { - status_var_decrement(thd->status_var.com_stat[SQLCOM_DROP_TABLE]); + status_var_decrement(thd->status_var.com_stat[lex->sql_command]); status_var_increment(thd->status_var.com_drop_tmp_table); /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ @@ -4503,10 +4787,13 @@ mysql_execute_command(THD *thd) } /* DDL and binlog write order are protected by metadata locks. */ - res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table()); + res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(), + lex->table_type == TABLE_TYPE_SEQUENCE); - /* when dropping temporary tables if @@session_track_state_change is ON then - send the boolean tracker in the OK packet */ + /* + When dropping temporary tables if @@session_track_state_change is ON + then send the boolean tracker in the OK packet + */ if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) { SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); @@ -4547,9 +4834,7 @@ mysql_execute_command(THD *thd) #endif case SQLCOM_CHANGE_DB: { - LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; - - if (!mysql_change_db(thd, &db_str, FALSE)) + if (!mysql_change_db(thd, &select_lex->db, FALSE)) my_ok(thd); break; @@ -4588,9 +4873,9 @@ mysql_execute_command(THD *thd) if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables, TRUE, 0))) goto error; - if (!(res= sql_set_variables(thd, lex_var_list, true))) + if (likely(!(res= sql_set_variables(thd, lex_var_list, true)))) { - if (!thd->is_error()) + if (likely(!thd->is_error())) my_ok(thd); } else @@ -4671,74 +4956,26 @@ mysql_execute_command(THD *thd) break; case SQLCOM_CREATE_DB: { - if (check_db_name(&lex->name)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); - break; - } - /* - If in a slave thread : - CREATE DATABASE DB was certainly not preceded by USE DB. - For that reason, db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, lex->create_info.or_replace() ? + if (prepare_db_action(thd, lex->create_info.or_replace() ? (CREATE_ACL | DROP_ACL) : CREATE_ACL, - lex->name.str, NULL, NULL, 1, 0)) + &lex->name)) break; - WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) - res= mysql_create_db(thd, lex->name.str, + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); + res= mysql_create_db(thd, &lex->name, lex->create_info, &lex->create_info); break; } case SQLCOM_DROP_DB: { - if (check_db_name(&lex->name)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); + if (prepare_db_action(thd, DROP_ACL, &lex->name)) break; - } - /* - If in a slave thread : - DROP DATABASE DB may not be preceded by USE DB. - For that reason, maybe db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(lex->name.str) || - !rpl_filter->db_ok_with_wild_table(lex->name.str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) - break; - WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL) - res= mysql_rm_db(thd, lex->name.str, lex->if_exists()); + WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); + res= mysql_rm_db(thd, &lex->name, lex->if_exists()); break; } case SQLCOM_ALTER_DB_UPGRADE: { - LEX_STRING *db= & lex->name; + LEX_CSTRING *db= &lex->name; #ifdef HAVE_REPLICATION if (thd->slave_thread) { @@ -4752,7 +4989,7 @@ mysql_execute_command(THD *thd) } } #endif - if (check_db_name(db)) + if (check_db_name((LEX_STRING*) db)) { my_error(ER_WRONG_DB_NAME, MYF(0), db->str); break; @@ -4764,7 +5001,7 @@ mysql_execute_command(THD *thd) res= 1; break; } - WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -4772,51 +5009,27 @@ mysql_execute_command(THD *thd) } case SQLCOM_ALTER_DB: { - LEX_STRING *db= &lex->name; - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db->str); - break; - } - /* - If in a slave thread : - ALTER DATABASE DB may not be preceded by USE DB. - For that reason, maybe db_ok() in sql/slave.cc did not check the - do_db/ignore_db. And as this query involves no tables, tables_ok() - above was not called. So we have to check rules again here. - */ -#ifdef HAVE_REPLICATION - if (thd->slave_thread) - { - rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; - if (!rpl_filter->db_ok(db->str) || - !rpl_filter->db_ok_with_wild_table(db->str)) - { - my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); - break; - } - } -#endif - if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) + LEX_CSTRING *db= &lex->name; + if (prepare_db_action(thd, ALTER_ACL, db)) break; - WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL) - res= mysql_alter_db(thd, db->str, &lex->create_info); + WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); + res= mysql_alter_db(thd, db, &lex->create_info); break; } case SQLCOM_SHOW_CREATE_DB: { char db_name_buff[NAME_LEN+1]; - LEX_STRING db_name; + LEX_CSTRING db_name; DBUG_EXECUTE_IF("4x_server_emul", my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;); db_name.str= db_name_buff; db_name.length= lex->name.length; - strmov(db_name.str, lex->name.str); + strmov(db_name_buff, lex->name.str); WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); break; @@ -4869,12 +5082,12 @@ mysql_execute_command(THD *thd) break; case SQLCOM_SHOW_CREATE_EVENT: WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - res= Events::show_create_event(thd, lex->spname->m_db, - lex->spname->m_name); + res= Events::show_create_event(thd, &lex->spname->m_db, + &lex->spname->m_name); break; case SQLCOM_DROP_EVENT: if (!(res= Events::drop_event(thd, - lex->spname->m_db, lex->spname->m_name, + &lex->spname->m_db, &lex->spname->m_name, lex->if_exists()))) my_ok(thd); break; @@ -4889,7 +5102,7 @@ mysql_execute_command(THD *thd) "mysql", NULL, NULL, 1, 0)) break; #ifdef HAVE_DLOPEN - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd); #else @@ -4907,7 +5120,7 @@ mysql_execute_command(THD *thd) "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list, lex->sql_command == SQLCOM_CREATE_ROLE))) @@ -4921,7 +5134,7 @@ mysql_execute_command(THD *thd) check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res= mysql_drop_user(thd, lex->users_list, lex->sql_command == SQLCOM_DROP_ROLE))) my_ok(thd); @@ -4934,7 +5147,7 @@ mysql_execute_command(THD *thd) check_global_access(thd,CREATE_USER_ACL)) break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (lex->sql_command == SQLCOM_ALTER_USER) res= mysql_alter_user(thd, lex->users_list); else @@ -4950,7 +5163,7 @@ mysql_execute_command(THD *thd) break; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); break; @@ -4960,7 +5173,7 @@ mysql_execute_command(THD *thd) { if (lex->type != TYPE_ENUM_PROXY && check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, - first_table ? first_table->db : select_lex->db, + first_table ? first_table->db.str : select_lex->db.str, first_table ? &first_table->grant.privilege : NULL, first_table ? &first_table->grant.m_internal : NULL, first_table ? 0 : 1, 0)) @@ -5000,19 +5213,18 @@ mysql_execute_command(THD *thd) } if (first_table) { - if (lex->type == TYPE_ENUM_PROCEDURE || - lex->type == TYPE_ENUM_FUNCTION) + const Sp_handler *sph= Sp_handler::handler((stored_procedure_type) + lex->type); + if (sph) { uint grants= lex->all_privileges ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL) : lex->grant; - if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, - lex->type == TYPE_ENUM_PROCEDURE, 0)) + if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0)) goto error; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - res= mysql_routine_grant(thd, all_tables, - lex->type == TYPE_ENUM_PROCEDURE, + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + res= mysql_routine_grant(thd, all_tables, sph, lex->users_list, grants, lex->sql_command == SQLCOM_REVOKE, TRUE); if (!res) @@ -5024,7 +5236,7 @@ mysql_execute_command(THD *thd) all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_table_grant(thd, all_tables, lex->users_list, lex->columns, lex->grant, lex->sql_command == SQLCOM_REVOKE); @@ -5040,9 +5252,9 @@ mysql_execute_command(THD *thd) } else { - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ - res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, + res= mysql_grant(thd, select_lex->db.str, lex->users_list, lex->grant, lex->sql_command == SQLCOM_REVOKE, lex->type == TYPE_ENUM_PROXY); } @@ -5066,7 +5278,7 @@ mysql_execute_command(THD *thd) case SQLCOM_REVOKE_ROLE: case SQLCOM_GRANT_ROLE: { - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if (!(res= mysql_grant_role(thd, lex->users_list, lex->sql_command != SQLCOM_GRANT_ROLE))) my_ok(thd); @@ -5124,7 +5336,7 @@ mysql_execute_command(THD *thd) REFRESH_STATUS | REFRESH_USER_RESOURCES)) { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); } #endif /* WITH_WSREP*/ @@ -5158,11 +5370,11 @@ mysql_execute_command(THD *thd) */ if (first_table) { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); + WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); } else { - WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); + WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); } } #endif /* WITH_WSREP */ @@ -5210,7 +5422,7 @@ mysql_execute_command(THD *thd) if (lex->kill_type == KILL_TYPE_ID || lex->kill_type == KILL_TYPE_QUERY) { Item *it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + if (it->fix_fields_if_needed_for_scalar(lex->thd, &it)) { my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -5408,173 +5620,14 @@ mysql_execute_command(THD *thd) break; case SQLCOM_CREATE_PROCEDURE: case SQLCOM_CREATE_SPFUNCTION: + case SQLCOM_CREATE_PACKAGE: + case SQLCOM_CREATE_PACKAGE_BODY: { - uint namelen; - char *name; - - DBUG_ASSERT(lex->sphead != 0); - DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ - /* - Verify that the database name is allowed, optionally - lowercase it. - */ - if (check_db_name(&lex->sphead->m_db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); - goto error; - } - - if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, - NULL, NULL, 0, 0)) - goto error; - - /* Checking the drop permissions if CREATE OR REPLACE is used */ - if (lex->create_info.or_replace()) - { - if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str, - lex->spname->m_name.str, - lex->sql_command == SQLCOM_CREATE_PROCEDURE, 0)) - goto error; - } - - name= lex->sphead->name(&namelen); -#ifdef HAVE_DLOPEN - if (lex->sphead->m_type == TYPE_ENUM_FUNCTION) - { - udf_func *udf = find_udf(name, namelen); - - if (udf) - { - my_error(ER_UDF_EXISTS, MYF(0), name); - goto error; - } - } -#endif - - if (sp_process_definer(thd)) - goto error; - - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - if (!sp_create_routine(thd, lex->sphead->m_type, lex->sphead)) - { -#ifndef NO_EMBEDDED_ACCESS_CHECKS - /* only add privileges if really neccessary */ - - Security_context security_context; - bool restore_backup_context= false; - Security_context *backup= NULL; - LEX_USER *definer= thd->lex->definer; - /* - We're going to issue an implicit GRANT statement so we close all - open tables. We have to keep metadata locks as this ensures that - this statement is atomic against concurent FLUSH TABLES WITH READ - LOCK. Deadlocks which can arise due to fact that this implicit - statement takes metadata locks should be detected by a deadlock - detector in MDL subsystem and reported as errors. - - No need to commit/rollback statement transaction, it's not started. - - TODO: Long-term we should either ensure that implicit GRANT statement - is written into binary log as a separate statement or make both - creation of routine and implicit GRANT parts of one fully atomic - statement. - */ - DBUG_ASSERT(thd->transaction.stmt.is_empty()); - close_thread_tables(thd); - /* - Check if the definer exists on slave, - then use definer privilege to insert routine privileges to mysql.procs_priv. - - For current user of SQL thread has GLOBAL_ACL privilege, - which doesn't any check routine privileges, - so no routine privilege record will insert into mysql.procs_priv. - */ - if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str)) - { - security_context.change_security_context(thd, - &thd->lex->definer->user, - &thd->lex->definer->host, - &thd->lex->sphead->m_db, - &backup); - restore_backup_context= true; - } - - if (sp_automatic_privileges && !opt_noacl && - check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, - lex->sphead->m_db.str, name, - lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) - { - if (sp_grant_privileges(thd, lex->sphead->m_db.str, name, - lex->sql_command == SQLCOM_CREATE_PROCEDURE)) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL)); - thd->clear_error(); - } - - /* - Restore current user with GLOBAL_ACL privilege of SQL thread - */ - if (restore_backup_context) - { - DBUG_ASSERT(thd->slave_thread == 1); - thd->security_ctx->restore_security_context(thd, backup); - } - -#endif - } - else + if (mysql_create_routine(thd, lex)) goto error; my_ok(thd); break; /* break super switch */ } /* end case group bracket */ - case SQLCOM_CALL: - { - sp_head *sp; - /* - 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, FALSE, - UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables, TRUE, 0)) - goto error; - - if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str, - lex->spname->m_name.str, TRUE, FALSE)) - goto error; - - /* - By this moment all needed SPs should be in cache so no need to look - into DB. - */ - if (!(sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname, - &thd->sp_proc_cache, TRUE))) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE", - lex->spname->m_qname.str); - goto error; - } - else - { - /* - Check that the stored procedure doesn't contain Dynamic SQL - and doesn't return result sets: such stored procedures can't - be called from a function or trigger. - */ - if (thd->in_sub_stmt) - { - const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? - "trigger" : "function"); - if (sp->is_not_allowed_in_function(where)) - goto error; - } - - if (do_execute_sp(thd, sp)) - goto error; - } - break; - } - case SQLCOM_COMPOUND: DBUG_ASSERT(all_tables == 0); DBUG_ASSERT(thd->in_sub_stmt == 0); @@ -5587,13 +5640,9 @@ mysql_execute_command(THD *thd) case SQLCOM_ALTER_FUNCTION: { int sp_result; - enum stored_procedure_type type; - type= (lex->sql_command == SQLCOM_ALTER_PROCEDURE ? - TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); - - if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str, - lex->spname->m_name.str, - lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0)) + const Sp_handler *sph= Sp_handler::handler(lex->sql_command); + if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, + &lex->spname->m_name, sph, 0)) goto error; /* @@ -5603,7 +5652,7 @@ mysql_execute_command(THD *thd) already puts on CREATE FUNCTION. */ /* Conditionally writes to binlog */ - sp_result= sp_update_routine(thd, type, lex->spname, &lex->sp_chistics); + sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics); switch (sp_result) { case SP_OK: @@ -5611,17 +5660,19 @@ mysql_execute_command(THD *thd) break; case SP_KEY_NOT_FOUND: my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + sph->type_str(), ErrConvDQName(lex->spname).ptr()); goto error; default: my_error(ER_SP_CANT_ALTER, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + sph->type_str(), ErrConvDQName(lex->spname).ptr()); goto error; } break; } case SQLCOM_DROP_PROCEDURE: case SQLCOM_DROP_FUNCTION: + case SQLCOM_DROP_PACKAGE: + case SQLCOM_DROP_PACKAGE_BODY: { #ifdef HAVE_DLOPEN if (lex->sql_command == SQLCOM_DROP_FUNCTION && @@ -5665,19 +5716,15 @@ mysql_execute_command(THD *thd) #endif int sp_result; - enum stored_procedure_type type; - type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ? - TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); - char *db= lex->spname->m_db.str; - char *name= lex->spname->m_name.str; - - if (check_routine_access(thd, ALTER_PROC_ACL, db, name, - lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) + const Sp_handler *sph= Sp_handler::handler(lex->sql_command); + + if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, &lex->spname->m_name, + Sp_handler::handler(lex->sql_command), 0)) goto error; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); /* Conditionally writes to binlog */ - sp_result= sp_drop_routine(thd, type, lex->spname); + sp_result= sph->sp_drop_routine(thd, lex->spname); #ifndef NO_EMBEDDED_ACCESS_CHECKS /* @@ -5700,8 +5747,8 @@ mysql_execute_command(THD *thd) if (sp_result != SP_KEY_NOT_FOUND && sp_automatic_privileges && !opt_noacl && - sp_revoke_privileges(thd, db, name, - lex->sql_command == SQLCOM_DROP_PROCEDURE)) + sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str, + Sp_handler::handler(lex->sql_command))) { push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_PROC_AUTO_REVOKE_FAIL, @@ -5722,51 +5769,52 @@ mysql_execute_command(THD *thd) res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST), - SP_COM_STRING(lex), lex->spname->m_qname.str); + sph->type_str(), + ErrConvDQName(lex->spname).ptr()); if (!res) my_ok(thd); break; } my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + sph->type_str(), ErrConvDQName(lex->spname).ptr()); goto error; default: my_error(ER_SP_DROP_FAILED, MYF(0), - SP_COM_STRING(lex), lex->spname->m_qname.str); + sph->type_str(), ErrConvDQName(lex->spname).ptr()); goto error; } break; } case SQLCOM_SHOW_CREATE_PROC: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname)) - goto error; - break; - } case SQLCOM_SHOW_CREATE_FUNC: + case SQLCOM_SHOW_CREATE_PACKAGE: + case SQLCOM_SHOW_CREATE_PACKAGE_BODY: { WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname)) - goto error; + const Sp_handler *sph= Sp_handler::handler(lex->sql_command); + if (sph->sp_show_create_routine(thd, lex->spname)) + goto error; break; } case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_FUNC_CODE: + case SQLCOM_SHOW_PACKAGE_BODY_CODE: { #ifndef DBUG_OFF + Database_qualified_name pkgname(&null_clex_str, &null_clex_str); sp_head *sp; - stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ? - TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); - + const Sp_handler *sph= Sp_handler::handler(lex->sql_command); WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); - if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp)) + if (sph->sp_resolve_package_routine(thd, thd->lex->sphead, + lex->spname, &sph, &pkgname)) + return true; + if (sph->sp_cache_routine(thd, lex->spname, false, &sp)) goto error; if (!sp || sp->show_routine_code(thd)) { /* We don't distinguish between errors for now */ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - SP_COM_STRING(lex), lex->spname->m_name.str); + sph->type_str(), lex->spname->m_name.str); goto error; } break; @@ -5791,9 +5839,9 @@ mysql_execute_command(THD *thd) { /* Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands - as specified through the thd->lex->create_view_mode flag. + as specified through the thd->lex->create_view->mode flag. */ - res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); + res= mysql_create_view(thd, first_table, thd->lex->create_view->mode); break; } case SQLCOM_DROP_VIEW: @@ -5801,7 +5849,7 @@ mysql_execute_command(THD *thd) if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; /* Conditionally writes to binlog. */ - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } @@ -5904,7 +5952,7 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); res= create_server(thd, &lex->server_options); break; @@ -5917,9 +5965,9 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); - if ((error= alter_server(thd, &lex->server_options))) + if (unlikely((error= alter_server(thd, &lex->server_options)))) { DBUG_PRINT("info", ("problem altering server <%s>", lex->server_options.server_name.str)); @@ -5937,7 +5985,7 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL)) break; - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); if ((err_code= drop_server(thd, &lex->server_options))) { @@ -5962,12 +6010,15 @@ mysql_execute_command(THD *thd) case SQLCOM_REPAIR: case SQLCOM_TRUNCATE: case SQLCOM_CREATE_TABLE: + case SQLCOM_CREATE_SEQUENCE: case SQLCOM_ALTER_TABLE: DBUG_ASSERT(first_table == all_tables && first_table != 0); /* fall through */ + case SQLCOM_ALTER_SEQUENCE: case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: case SQLCOM_GET_DIAGNOSTICS: + case SQLCOM_CALL: DBUG_ASSERT(lex->m_sql_cmd != NULL); res= lex->m_sql_cmd->execute(thd); break; @@ -6014,8 +6065,12 @@ finish: } thd->reset_kill_query(); } - if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) + if (unlikely(thd->is_error()) || + (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) + { + THD_STAGE_INFO(thd, stage_rollback); trans_rollback_stmt(thd); + } #ifdef WITH_WSREP else if (thd->spcont && (thd->wsrep_conflict_state == MUST_ABORT || @@ -6038,6 +6093,7 @@ finish: else { /* If commit fails, we should be able to reset the OK status. */ + THD_STAGE_INFO(thd, stage_commit); thd->get_stmt_da()->set_overwrite_status(true); trans_commit_stmt(thd); thd->get_stmt_da()->set_overwrite_status(false); @@ -6047,12 +6103,13 @@ finish: #endif } - /* Free tables */ + /* Free tables. Set stage 'closing tables' */ close_thread_tables(thd); #ifdef WITH_WSREP thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK; #endif /* WITH_WSREP */ + #ifndef DBUG_OFF if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt) DEBUG_SYNC(thd, "execute_command_after_close_tables"); @@ -6070,6 +6127,7 @@ finish: one of storage engines (e.g. due to deadlock). Rollback transaction in all storage engines including binary log. */ + THD_STAGE_INFO(thd, stage_rollback_implicit); trans_rollback_implicit(thd); thd->mdl_context.release_transactional_locks(); } @@ -6079,6 +6137,7 @@ finish: DBUG_ASSERT(! thd->in_sub_stmt); if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) { + THD_STAGE_INFO(thd, stage_commit_implicit); /* If commit fails, we should be able to reset the OK status. */ thd->get_stmt_da()->set_overwrite_status(true); /* Commit the normal transaction if one is active. */ @@ -6106,6 +6165,8 @@ finish: thd->mdl_context.release_statement_locks(); } + THD_STAGE_INFO(thd, stage_starting_cleanup); + TRANSACT_TRACKER(add_trx_state_from_thd(thd)); WSREP_TO_ISOLATION_END; @@ -6153,7 +6214,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) to prepend EXPLAIN to any query and receive output for it, even if the query itself redirects the output. */ - if (!(result= new (thd->mem_root) select_send(thd))) + if (unlikely(!(result= new (thd->mem_root) select_send(thd)))) return 1; /* purecov: inspected */ thd->send_explain_fields(result, lex->describe, lex->analyze_stmt); @@ -6164,7 +6225,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) res= mysql_explain_union(thd, &lex->unit, result); /* Print EXPLAIN only if we don't have an error */ - if (!res) + if (likely(!res)) { /* Do like the original select_describe did: remove OFFSET from the @@ -6335,11 +6396,11 @@ static bool check_rename_table(THD *thd, TABLE_LIST *first_table, TABLE_LIST *table; for (table= first_table; table; table= table->next_local->next_local) { - if (check_access(thd, ALTER_ACL | DROP_ACL, table->db, + if (check_access(thd, ALTER_ACL | DROP_ACL, table->db.str, &table->grant.privilege, &table->grant.m_internal, 0, 0) || - check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db, + check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db.str, &table->next_local->grant.privilege, &table->next_local->grant.m_internal, 0, 0)) @@ -6432,13 +6493,15 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, dummy= 0; } - THD_STAGE_INFO(thd, stage_checking_permissions); - if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) + /* check access may be called twice in a row. Don't change to same stage */ + if (thd->proc_info != stage_checking_permissions.m_name) + THD_STAGE_INFO(thd, stage_checking_permissions); + if (unlikely((!db || !db[0]) && !thd->db.str && !dont_check_global_grants)) { DBUG_RETURN(FALSE); // CTE reference or an error later } - if ((db != NULL) && (db != any_db)) + if (likely((db != NULL) && (db != any_db))) { /* Check if this is reserved database, like information schema or @@ -6485,7 +6548,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, */ if (!(sctx->master_access & SELECT_ACL)) { - if (db && (!thd->db || db_is_pattern || strcmp(db, thd->db))) + if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) { db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, db_is_pattern); @@ -6508,8 +6571,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, *save_priv|= sctx->master_access; DBUG_RETURN(FALSE); } - if (((want_access & ~sctx->master_access) & ~DB_ACLS) || - (! db && dont_check_global_grants)) + if (unlikely(((want_access & ~sctx->master_access) & ~DB_ACLS) || + (! db && dont_check_global_grants))) { // We can never grant this DBUG_PRINT("error",("No possible access")); if (!no_errors) @@ -6525,7 +6588,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_RETURN(TRUE); /* purecov: tested */ } - if (db == any_db) + if (unlikely(db == any_db)) { /* Access granted; Allow select on *any* db. @@ -6534,7 +6597,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, DBUG_RETURN(FALSE); } - if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))) + if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) { db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, db_is_pattern); @@ -6589,8 +6652,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, status_var_increment(thd->status_var.access_denied_errors); my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, - (db ? db : (thd->db ? - thd->db : + (db ? db : (thd->db.str ? + thd->db.str : "unknown"))); } DBUG_RETURN(TRUE); @@ -6628,7 +6691,7 @@ bool check_single_table_access(THD *thd, ulong privilege, !all_tables->schema_table) db_name= all_tables->view_db.str; else - db_name= all_tables->db; + db_name= all_tables->db.str; if (check_access(thd, privilege, db_name, &all_tables->grant.privilege, @@ -6717,7 +6780,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) case SCH_TRIGGERS: case SCH_EVENTS: { - const char *dst_db_name= table->schema_select_lex->db; + const char *dst_db_name= table->schema_select_lex->db.str; DBUG_ASSERT(dst_db_name); @@ -6752,7 +6815,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) if (thd->open_temporary_tables(dst_table)) return TRUE; - if (check_access(thd, SELECT_ACL, dst_table->db, + if (check_access(thd, SELECT_ACL, dst_table->db.str, &dst_table->grant.privilege, &dst_table->grant.m_internal, FALSE, FALSE)) @@ -6862,6 +6925,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, thd->security_ctx= sctx; + if (table_ref->sequence) + { + /* We want to have either SELECT or INSERT rights to sequences depending + on how they are accessed + */ + want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? + INSERT_ACL : SELECT_ACL); + } + if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, @@ -6879,14 +6951,15 @@ deny: bool -check_routine_access(THD *thd, ulong want_access,char *db, char *name, - bool is_proc, bool no_errors) +check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db, + const LEX_CSTRING *name, + const Sp_handler *sph, bool no_errors) { TABLE_LIST tables[1]; bzero((char *)tables, sizeof(TABLE_LIST)); - tables->db= db; - tables->table_name= tables->alias= name; + tables->db= *db; + tables->table_name= tables->alias= *name; /* The following test is just a shortcut for check_access() (to avoid @@ -6903,13 +6976,13 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name, DBUG_ASSERT((want_access & CREATE_PROC_ACL) == 0); if ((thd->security_ctx->master_access & want_access) == want_access) tables->grant.privilege= want_access; - else if (check_access(thd, want_access, db, + else if (check_access(thd, want_access, db->str, &tables->grant.privilege, &tables->grant.m_internal, 0, no_errors)) return TRUE; - return check_grant_routine(thd, want_access, tables, is_proc, no_errors); + return check_grant_routine(thd, want_access, tables, sph, no_errors); } @@ -6927,7 +7000,7 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name, */ bool check_some_routine_access(THD *thd, const char *db, const char *name, - bool is_proc) + const Sp_handler *sph) { ulong save_priv; /* @@ -6944,7 +7017,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name, if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) || (save_priv & SHOW_PROC_ACLS)) return FALSE; - return check_routine_level_acl(thd, db, name, is_proc); + return check_routine_level_acl(thd, db, name, sph); } @@ -6970,7 +7043,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) { if (access & want_access) { - if (!check_access(thd, access, table->db, + if (!check_access(thd, access, table->db.str, &table->grant.privilege, &table->grant.m_internal, 0, 1) && @@ -7009,7 +7082,7 @@ bool check_global_access(THD *thd, ulong want_access, bool no_errors) char command[128]; if ((thd->security_ctx->master_access & want_access)) return 0; - if (!no_errors) + if (unlikely(!no_errors)) { get_privilege_desc(command, sizeof(command), want_access); my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); @@ -7052,8 +7125,8 @@ bool check_fk_parent_table_access(THD *thd, TABLE_LIST parent_table; bool is_qualified_table_name; Foreign_key *fk_key= (Foreign_key *)key; - LEX_STRING db_name; - LEX_STRING table_name= { fk_key->ref_table.str, + LEX_CSTRING db_name; + LEX_CSTRING table_name= { fk_key->ref_table.str, fk_key->ref_table.length }; const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | REFERENCES_ACL); @@ -7069,12 +7142,13 @@ bool check_fk_parent_table_access(THD *thd, if (fk_key->ref_db.str) { is_qualified_table_name= true; - db_name.str= (char *) thd->memdup(fk_key->ref_db.str, - fk_key->ref_db.length+1); + if (!(db_name.str= (char *) thd->memdup(fk_key->ref_db.str, + fk_key->ref_db.length+1))) + return true; db_name.length= fk_key->ref_db.length; // Check if database name is valid or not. - if (fk_key->ref_db.str && check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); return true; @@ -7082,13 +7156,16 @@ bool check_fk_parent_table_access(THD *thd, } else { - if (!thd->db) + if (!thd->db.str) { - db_name.str= (char *) thd->memdup(create_db, strlen(create_db)+1); + DBUG_ASSERT(create_db); db_name.length= strlen(create_db); + if (!(db_name.str= (char *) thd->memdup(create_db, + db_name.length+1))) + return true; is_qualified_table_name= true; - if(create_db && check_db_name(&db_name)) + if (check_db_name((LEX_STRING*) &db_name)) { my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); return true; @@ -7096,7 +7173,7 @@ bool check_fk_parent_table_access(THD *thd, } else { - if (thd->lex->copy_db_to(&db_name.str, &db_name.length)) + if (thd->lex->copy_db_to(&db_name)) return true; else is_qualified_table_name= false; @@ -7106,15 +7183,14 @@ bool check_fk_parent_table_access(THD *thd, // if lower_case_table_names is set then convert tablename to lower case. if (lower_case_table_names) { - table_name.str= (char *) thd->memdup(fk_key->ref_table.str, - fk_key->ref_table.length+1); - table_name.length= my_casedn_str(files_charset_info, table_name.str); - db_name.length = my_casedn_str(files_charset_info, db_name.str); + char *name; + table_name.str= name= (char *) thd->memdup(fk_key->ref_table.str, + fk_key->ref_table.length+1); + table_name.length= my_casedn_str(files_charset_info, name); + db_name.length= my_casedn_str(files_charset_info, (char*) db_name.str); } - parent_table.init_one_table(db_name.str, db_name.length, - table_name.str, table_name.length, - table_name.str, TL_IGNORE); + parent_table.init_one_table(&db_name, &table_name, 0, TL_IGNORE); /* Check if user has any of the "privileges" at table level on @@ -7199,16 +7275,16 @@ bool check_stack_overrun(THD *thd, long margin, #define MY_YACC_INIT 1000 // Start with big alloc #define MY_YACC_MAX 32000 // Because of 'short' -bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) +bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, size_t *yystacksize) { Yacc_state *state= & current_thd->m_parser_state->m_yacc; - ulong old_info=0; + size_t old_info=0; DBUG_ASSERT(state); - if ((uint) *yystacksize >= MY_YACC_MAX) + if ( *yystacksize >= MY_YACC_MAX) return 1; if (!state->yacc_yyvs) old_info= *yystacksize; - *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); + *yystacksize= set_zone((int)(*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); if (!(state->yacc_yyvs= (uchar*) my_realloc(state->yacc_yyvs, *yystacksize*sizeof(**yyvs), @@ -7249,17 +7325,16 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) void THD::reset_for_next_command(bool do_clear_error) { - THD *thd= this; DBUG_ENTER("THD::reset_for_next_command"); - DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */ - DBUG_ASSERT(! thd->in_sub_stmt); + DBUG_ASSERT(!spcont); /* not for substatements of routines */ + DBUG_ASSERT(!in_sub_stmt); - if (do_clear_error) + if (likely(do_clear_error)) clear_error(1); - thd->free_list= 0; + free_list= 0; /* - We also assign thd->stmt_lex in lex_start(), but during bootstrap this + We also assign stmt_lex in lex_start(), but during bootstrap this code is executed first. */ DBUG_ASSERT(lex == &main_lex); @@ -7269,8 +7344,8 @@ void THD::reset_for_next_command(bool do_clear_error) Those two lines below are theoretically unneeded as THD::cleanup_after_query() should take care of this already. */ - thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty(); - thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; + auto_inc_intervals_in_cur_stmt_for_binlog.empty(); + stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; #ifdef WITH_WSREP /* @@ -7281,58 +7356,56 @@ void THD::reset_for_next_command(bool do_clear_error) use autoinc values passed in binlog events, not the values forced by the cluster. */ - if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE && - !thd->slave_thread && wsrep_auto_increment_control) + if (WSREP(this) && wsrep_exec_mode == LOCAL_STATE && + !slave_thread && wsrep_auto_increment_control) { - thd->variables.auto_increment_offset= + variables.auto_increment_offset= global_system_variables.auto_increment_offset; - thd->variables.auto_increment_increment= + variables.auto_increment_increment= global_system_variables.auto_increment_increment; } #endif /* WITH_WSREP */ - thd->query_start_used= 0; - thd->query_start_sec_part_used= 0; - thd->is_fatal_error= thd->time_zone_used= 0; - thd->log_current_statement= 0; + query_start_sec_part_used= 0; + is_fatal_error= time_zone_used= 0; + log_current_statement= 0; /* Clear the status flag that are expected to be cleared at the beginning of each SQL statement. */ - thd->server_status&= ~SERVER_STATUS_CLEAR_SET; + server_status&= ~SERVER_STATUS_CLEAR_SET; /* If in autocommit mode and not in a transaction, reset OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings in ha_rollback_trans() about some tables couldn't be rolled back. */ - if (!thd->in_multi_stmt_transaction_mode()) + if (!in_multi_stmt_transaction_mode()) { - thd->variables.option_bits&= ~OPTION_KEEP_LOG; - thd->transaction.all.reset(); + variables.option_bits&= ~OPTION_KEEP_LOG; + transaction.all.reset(); } - DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx); - thd->thread_specific_used= FALSE; + DBUG_ASSERT(security_ctx== &main_security_ctx); + thread_specific_used= FALSE; if (opt_bin_log) - reset_dynamic(&thd->user_var_events); - DBUG_ASSERT(thd->user_var_events_alloc == &thd->main_mem_root); + reset_dynamic(&user_var_events); + DBUG_ASSERT(user_var_events_alloc == &main_mem_root); + enable_slow_log= true; + get_stmt_da()->reset_for_next_command(); + rand_used= 0; + m_sent_row_count= m_examined_row_count= 0; + accessed_rows_and_keys= 0; - 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; + reset_slow_query_state(); - thd->query_plan_flags= QPLAN_INIT; - thd->query_plan_fsort_passes= 0; - - thd->reset_current_stmt_binlog_format_row(); - thd->binlog_unsafe_warning_flags= 0; + reset_current_stmt_binlog_format_row(); + binlog_unsafe_warning_flags= 0; - thd->save_prep_leaf_list= false; + save_prep_leaf_list= false; DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row(): %d", - thd->is_current_stmt_binlog_format_row())); + is_current_stmt_binlog_format_row())); DBUG_VOID_RETURN; } @@ -7373,18 +7446,21 @@ mysql_init_select(LEX *lex) */ bool -mysql_new_select(LEX *lex, bool move_down) +mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) { - SELECT_LEX *select_lex; THD *thd= lex->thd; + bool new_select= select_lex == NULL; DBUG_ENTER("mysql_new_select"); - if (!(select_lex= new (thd->mem_root) SELECT_LEX())) - DBUG_RETURN(1); - select_lex->select_number= ++thd->lex->stmt_lex->current_select_number; - select_lex->parent_lex= lex; /* Used in init_query. */ - select_lex->init_query(); - select_lex->init_select(); + if (new_select) + { + if (!(select_lex= new (thd->mem_root) SELECT_LEX())) + DBUG_RETURN(1); + select_lex->select_number= ++thd->lex->stmt_lex->current_select_number; + select_lex->parent_lex= lex; /* Used in init_query. */ + select_lex->init_query(); + select_lex->init_select(); + } lex->nest_level++; if (lex->nest_level > (int) MAX_SELECT_NESTING) { @@ -7396,13 +7472,11 @@ mysql_new_select(LEX *lex, bool move_down) if (move_down) { SELECT_LEX_UNIT *unit; - lex->subqueries= TRUE; /* first select_lex of subselect or derived table */ if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) DBUG_RETURN(1); unit->init_query(); - unit->init_select(); unit->thd= thd; unit->include_down(lex->current_select); unit->link_next= 0; @@ -7455,7 +7529,8 @@ mysql_new_select(LEX *lex, bool move_down) unit->first_select()->context.outer_context; } - select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); + if (new_select) + select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; /* in subquery is SELECT query and we allow resolution of names in SELECT @@ -7475,28 +7550,23 @@ mysql_new_select(LEX *lex, bool move_down) @param var_name Variable name */ -void create_select_for_variable(const char *var_name) +void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) { - THD *thd; LEX *lex; - LEX_STRING tmp; Item *var; char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end; DBUG_ENTER("create_select_for_variable"); - thd= current_thd; lex= thd->lex; mysql_init_select(lex); lex->sql_command= SQLCOM_SELECT; - tmp.str= (char*) var_name; - tmp.length=strlen(var_name); /* We set the name of Item to @@session.var_name because that then is used as the column name in the output. */ - if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_str))) + if ((var= get_system_var(thd, OPT_SESSION, var_name, &null_clex_str))) { - end= strxmov(buff, "@@session.", var_name, NullS); + end= strxmov(buff, "@@session.", var_name->str, NullS); var->set_name(thd, buff, (uint)(end-buff), system_charset_info); add_item_to_list(thd, var); } @@ -7711,7 +7781,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool err= parse_sql(thd, parser_state, NULL, true); - if (!err) + if (likely(!err)) { thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, @@ -7726,7 +7796,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, else #endif { - if (! thd->is_error()) + if (likely(! thd->is_error())) { const char *found_semicolon= parser_state->m_lip.found_semicolon; /* @@ -7751,7 +7821,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, lex->set_trg_event_type_for_tables(); MYSQL_QUERY_EXEC_START(thd->query(), thd->thread_id, - (char *) (thd->db ? thd->db : ""), + thd->get_db(), &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 0); @@ -7776,6 +7846,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, THD_STAGE_INFO(thd, stage_freeing_items); sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); + sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size); + sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size); thd->end_statement(); thd->cleanup_after_query(); DBUG_ASSERT(thd->Item_change_list::is_empty()); @@ -7818,7 +7890,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) DBUG_ENTER("mysql_test_parse_for_slave"); Parser_state parser_state; - if (!(error= parser_state.init(thd, rawbuf, length))) + if (likely(!(error= parser_state.init(thd, rawbuf, length)))) { lex_start(thd); thd->reset_for_next_command(); @@ -7840,7 +7912,7 @@ add_proc_to_list(THD* thd, Item *item) ORDER *order; Item **item_ptr; - if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*)))) + if (unlikely(!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))) return 1; item_ptr = (Item**) (order+1); *item_ptr= item; @@ -7858,7 +7930,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) { ORDER *order; DBUG_ENTER("add_to_list"); - if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)))) + if (unlikely(!(order = (ORDER *) thd->alloc(sizeof(ORDER))))) DBUG_RETURN(1); order->item_ptr= item; order->item= &order->item_ptr; @@ -7893,7 +7965,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Table_ident *table, - LEX_STRING *alias, + LEX_CSTRING *alias, ulong table_options, thr_lock_type lock_type, enum_mdl_type mdl_type, @@ -7903,47 +7975,48 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, { TABLE_LIST *ptr; TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */ - char *alias_str; + LEX_CSTRING alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); - if (!table) + if (unlikely(!table)) DBUG_RETURN(0); // End of memory - alias_str= alias ? alias->str : table->table.str; + alias_str= alias ? *alias : table->table; + DBUG_ASSERT(alias_str.str); if (!MY_TEST(table_options & TL_OPTION_ALIAS) && - check_table_name(table->table.str, table->table.length, FALSE)) + unlikely(check_table_name(table->table.str, table->table.length, FALSE))) { my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str); DBUG_RETURN(0); } - if (table->is_derived_table() == FALSE && table->db.str && - check_db_name(&table->db)) + if (unlikely(table->is_derived_table() == FALSE && table->db.str && + check_db_name((LEX_STRING*) &table->db))) { my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str); DBUG_RETURN(0); } - if (!alias) /* Alias is case sensitive */ + if (!alias) /* Alias is case sensitive */ { - if (table->sel) + if (unlikely(table->sel)) { my_message(ER_DERIVED_MUST_HAVE_ALIAS, ER_THD(thd, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0)); DBUG_RETURN(0); } - if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1))) + /* alias_str points to table->table; Let's make a copy */ + if (unlikely(!(alias_str.str= (char*) thd->memdup(alias_str.str, alias_str.length+1)))) DBUG_RETURN(0); } - if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) + if (unlikely(!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))) DBUG_RETURN(0); /* purecov: inspected */ if (table->db.str) { ptr->is_fqtn= TRUE; - ptr->db= table->db.str; - ptr->db_length= table->db.length; + ptr->db= table->db; } - else if (lex->copy_db_to(&ptr->db, &ptr->db_length)) + else if (lex->copy_db_to(&ptr->db)) DBUG_RETURN(0); else ptr->is_fqtn= FALSE; @@ -7953,20 +8026,21 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (lower_case_table_names) { if (table->table.length) - table->table.length= my_casedn_str(files_charset_info, table->table.str); - if (ptr->db_length && ptr->db != any_db) - ptr->db_length= my_casedn_str(files_charset_info, ptr->db); + table->table.length= my_casedn_str(files_charset_info, + (char*) table->table.str); + if (ptr->db.length && ptr->db.str != any_db) + ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str); } - ptr->table_name=table->table.str; - ptr->table_name_length=table->table.length; + ptr->table_name= table->table; ptr->lock_type= lock_type; ptr->updating= MY_TEST(table_options & TL_OPTION_UPDATING); /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES); + ptr->sequence= MY_TEST(table_options & TL_OPTION_SEQUENCE); ptr->derived= table->sel; - if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length)) + if (!ptr->derived && is_infoschema_db(&ptr->db)) { if (ptr->updating && /* Special cases which are processed by commands itself */ @@ -7980,7 +8054,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, DBUG_RETURN(0); } ST_SCHEMA_TABLE *schema_table; - schema_table= find_schema_table(thd, ptr->table_name); + schema_table= find_schema_table(thd, &ptr->table_name); ptr->schema_table_name= ptr->table_name; ptr->schema_table= schema_table; } @@ -7992,8 +8066,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->cacheable_table= !table->is_derived_table(); ptr->index_hints= index_hints_arg; ptr->option= option ? option->str : 0; - /* check that used name is unique */ - if (lock_type != TL_IGNORE) + /* check that used name is unique. Sequences are ignored */ + if (lock_type != TL_IGNORE && !ptr->sequence) { TABLE_LIST *first_table= table_list.first; if (lex->sql_command == SQLCOM_CREATE_VIEW) @@ -8002,16 +8076,17 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, tables ; tables=tables->next_local) { - if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) && - !strcmp(ptr->db, tables->db)) + if (unlikely(!my_strcasecmp(table_alias_charset, alias_str.str, + tables->alias.str) && + !cmp(&ptr->db, &tables->db) && ! tables->sequence)) { - my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */ + my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str.str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ } } } /* Store the table reference preceding the current one. */ - if (table_list.elements > 0) + if (table_list.elements > 0 && likely(!ptr->sequence)) { /* table_list.next points to the last inserted TABLE_LIST->next_local' @@ -8036,8 +8111,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Notice that as a side effect here we set the next_local field of the previous table reference to 'ptr'. Here we also add one element to the list 'table_list'. + We don't store sequences into the local list to hide them from INSERT + and SELECT. */ - table_list.link_in_list(ptr, &ptr->next_local); + if (likely(!ptr->sequence)) + 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; @@ -8046,9 +8124,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, lex->add_to_query_tables(ptr); // Pure table aliases do not need to be locked: - if (ptr->db && !(table_options & TL_OPTION_ALIAS)) + if (ptr->db.str && !(table_options & TL_OPTION_ALIAS)) { - ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type, + ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str, + mdl_type, MDL_TRANSACTION); } DBUG_RETURN(ptr); @@ -8080,16 +8159,18 @@ bool st_select_lex::init_nested_join(THD *thd) NESTED_JOIN *nested_join; DBUG_ENTER("init_nested_join"); - if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ - sizeof(NESTED_JOIN)))) + if (unlikely(!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ + sizeof(NESTED_JOIN))))) DBUG_RETURN(1); nested_join= ptr->nested_join= ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); - join_list->push_front(ptr, thd->mem_root); + if (unlikely(join_list->push_front(ptr, thd->mem_root))) + DBUG_RETURN(1); ptr->embedding= embedding; ptr->join_list= join_list; - ptr->alias= (char*) "(nested_join)"; + ptr->alias.str="(nested_join)"; + ptr->alias.length= sizeof("(nested_join)")-1; embedding= ptr; join_list= &nested_join->join_list; join_list->empty(); @@ -8169,16 +8250,16 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) { DBUG_RETURN(head); } - - if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ - sizeof(NESTED_JOIN)))) + if (unlikely(!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ + sizeof(NESTED_JOIN))))) DBUG_RETURN(0); nested_join= ptr->nested_join= ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); ptr->embedding= embedding; ptr->join_list= join_list; - ptr->alias= (char*) "(nest_last_join)"; + ptr->alias.str= "(nest_last_join)"; + ptr->alias.length= sizeof("(nest_last_join)")-1; embedded_list= &nested_join->join_list; embedded_list->empty(); nested_join->nest_type= JOIN_OP_NEST; @@ -8186,7 +8267,7 @@ 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) + if (unlikely(!table)) DBUG_RETURN(NULL); table->join_list= embedded_list; table->embedding= ptr; @@ -8460,7 +8541,8 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op, cj_nest->on_expr= tbl->on_expr; cj_nest->embedding= tbl->embedding; cj_nest->join_list= jl; - cj_nest->alias= (char*) "(nest_last_join)"; + cj_nest->alias.str= "(nest_last_join)"; + cj_nest->alias.length= sizeof("(nest_last_join)"); li.replace(cj_nest); /* @@ -8563,8 +8645,8 @@ void st_select_lex::prepare_add_window_spec(THD *thd) } bool st_select_lex::add_window_def(THD *thd, - LEX_STRING *win_name, - LEX_STRING *win_ref, + LEX_CSTRING *win_name, + LEX_CSTRING *win_ref, SQL_I_List<ORDER> win_partition_list, SQL_I_List<ORDER> win_order_list, Window_frame *win_frame) @@ -8586,7 +8668,7 @@ bool st_select_lex::add_window_def(THD *thd, } bool st_select_lex::add_window_spec(THD *thd, - LEX_STRING *win_ref, + LEX_CSTRING *win_ref, SQL_I_List<ORDER> win_partition_list, SQL_I_List<ORDER> win_order_list, Window_frame *win_frame) @@ -8686,7 +8768,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->nest_level_base= first_select()->nest_level_base; fake_select_lex->nest_level=first_select()->nest_level; - if (!is_union()) + if (!is_unit_op()) { /* This works only for @@ -8836,13 +8918,13 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, /** - Find a thread by id and return it, locking it LOCK_thd_data + Find a thread by id and return it, locking it LOCK_thd_kill @param id Identifier of the thread we're looking for @param query_id If true, search by query_id instead of thread_id @return NULL - not found - pointer - thread found, and its LOCK_thd_data is locked. + pointer - thread found, and its LOCK_thd_kill is locked. */ THD *find_thread_by_id(longlong id, bool query_id) @@ -8856,7 +8938,7 @@ THD *find_thread_by_id(longlong id, bool query_id) continue; if (id == (query_id ? tmp->query_id : (longlong) tmp->thread_id)) { - mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -8912,13 +8994,13 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ thd->security_ctx->user_matches(tmp->security_ctx)) && !wsrep_thd_is_BF(tmp, false)) { - tmp->awake(kill_signal); + tmp->awake_no_mutex(kill_signal); error=0; } else error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : ER_KILL_DENIED_ERROR); - mysql_mutex_unlock(&tmp->LOCK_thd_data); + mysql_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); DBUG_RETURN(error); @@ -8948,7 +9030,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, *rows= 0; - if (thd->is_fatal_error) // If we run out of memory + if (unlikely(thd->is_fatal_error)) // If we run out of memory DBUG_RETURN(ER_OUT_OF_RESOURCES); DBUG_PRINT("enter", ("user: %s signal: %u", user->user.str, @@ -8976,7 +9058,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, DBUG_RETURN(ER_KILL_DENIED_ERROR); } if (!threads_to_kill.push_back(tmp, thd->mem_root)) - mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete } } mysql_mutex_unlock(&LOCK_thread_count); @@ -8987,17 +9069,17 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, THD *ptr= it2++; do { - ptr->awake(kill_signal); + ptr->awake_no_mutex(kill_signal); /* Careful here: The list nodes are allocated on the memroots of the THDs to be awakened. But those THDs may be terminated and deleted as soon as we release - LOCK_thd_data, which will make the list nodes invalid. + LOCK_thd_kill, which will make the list nodes invalid. Since the operation "it++" dereferences the "next" pointer of the - previous list node, we need to do this while holding LOCK_thd_data. + previous list node, we need to do this while holding LOCK_thd_kill. */ next_ptr= it2++; - mysql_mutex_unlock(&ptr->LOCK_thd_data); + mysql_mutex_unlock(&ptr->LOCK_thd_kill); (*rows)++; } while ((ptr= next_ptr)); } @@ -9018,7 +9100,7 @@ static void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) { uint error; - if (!(error= kill_one_thread(thd, id, state, type))) + if (likely(!(error= kill_one_thread(thd, id, state, type)))) { if (!thd->killed) my_ok(thd); @@ -9035,7 +9117,7 @@ void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) { uint error; ha_rows rows; - if (!(error= kill_threads_for_user(thd, user, state, &rows))) + if (likely(!(error= kill_threads_for_user(thd, user, state, &rows)))) my_ok(thd, rows); else { @@ -9051,14 +9133,14 @@ void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) /** If pointer is not a null pointer, append filename to it. */ bool append_file_to_dir(THD *thd, const char **filename_ptr, - const char *table_name) + const LEX_CSTRING *table_name) { char buff[FN_REFLEN],*ptr, *end; if (!*filename_ptr) return 0; // nothing to do /* Check that the filename is not too long and it's a hard path */ - if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 || + if (strlen(*filename_ptr)+table_name->length >= FN_REFLEN-1 || !test_if_hard_path(*filename_ptr)) { my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr); @@ -9067,36 +9149,11 @@ bool append_file_to_dir(THD *thd, const char **filename_ptr, /* Fix is using unix filename format on dos */ strmov(buff,*filename_ptr); end=convert_dirname(buff, *filename_ptr, NullS); - if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1))) + if (unlikely(!(ptr= (char*) thd->alloc((size_t) (end-buff) + + table_name->length + 1)))) return 1; // End of memory *filename_ptr=ptr; - strxmov(ptr,buff,table_name,NullS); - return 0; -} - - -/** - Check if the select is a simple select (not an union). - - @retval - 0 ok - @retval - 1 error ; In this case the error messege is sent to the client -*/ - -bool check_simple_select() -{ - THD *thd= current_thd; - LEX *lex= thd->lex; - if (lex->current_select != &lex->select_lex) - { - char command[80]; - Lex_input_stream *lip= & thd->m_parser_state->m_lip; - strmake(command, lip->yylval->symbol.str, - MY_MIN(lip->yylval->symbol.length, sizeof(command)-1)); - my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command); - return 1; - } + strxmov(ptr,buff,table_name->str,NullS); return 0; } @@ -9185,7 +9242,6 @@ Item * all_any_subquery_creator(THD *thd, Item *left_expr, bool multi_update_precheck(THD *thd, TABLE_LIST *tables) { - const char *msg= 0; TABLE_LIST *table; LEX *lex= thd->lex; SELECT_LEX *select_lex= &lex->select_lex; @@ -9206,12 +9262,12 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) continue; if (table->derived) table->grant.privilege= SELECT_ACL; - else if ((check_access(thd, UPDATE_ACL, table->db, + else if ((check_access(thd, UPDATE_ACL, table->db.str, &table->grant.privilege, &table->grant.m_internal, 0, 1) || check_grant(thd, UPDATE_ACL, table, FALSE, 1, TRUE)) && - (check_access(thd, SELECT_ACL, table->db, + (check_access(thd, SELECT_ACL, table->db.str, &table->grant.privilege, &table->grant.m_internal, 0, 0) || @@ -9231,7 +9287,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) { if (!table->table_in_first_from_clause) { - if (check_access(thd, SELECT_ACL, table->db, + if (check_access(thd, SELECT_ACL, table->db.str, &table->grant.privilege, &table->grant.m_internal, 0, 0) || @@ -9241,15 +9297,6 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) } } - if (select_lex->order_list.elements) - msg= "ORDER BY"; - else if (select_lex->select_limit) - msg= "LIMIT"; - if (msg) - { - my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg); - DBUG_RETURN(TRUE); - } DBUG_RETURN(FALSE); } @@ -9338,25 +9385,25 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl, for (TABLE_LIST *elem= tables; elem; elem= elem->next_local) { - int cmp; + int res; if (tbl->is_fqtn && elem->is_alias) continue; /* no match */ if (tbl->is_fqtn && elem->is_fqtn) - cmp= my_strcasecmp(table_alias_charset, tbl->table_name, elem->table_name) || - strcmp(tbl->db, elem->db); + res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) || + cmp(&tbl->db, &elem->db)); else if (elem->is_alias) - cmp= my_strcasecmp(table_alias_charset, tbl->alias, elem->alias); + res= my_strcasecmp(table_alias_charset, tbl->alias.str, elem->alias.str); else - cmp= my_strcasecmp(table_alias_charset, tbl->table_name, elem->table_name) || - strcmp(tbl->db, elem->db); + res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) || + cmp(&tbl->db, &elem->db)); - if (cmp) + if (res) continue; if (match) { - my_error(ER_NONUNIQ_TABLE, MYF(0), elem->alias); + my_error(ER_NONUNIQ_TABLE, MYF(0), elem->alias.str); DBUG_RETURN(NULL); } @@ -9364,7 +9411,7 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl, } if (!match) - my_error(ER_UNKNOWN_TABLE, MYF(0), tbl->table_name, "MULTI DELETE"); + my_error(ER_UNKNOWN_TABLE, MYF(0), tbl->table_name.str, "MULTI DELETE"); DBUG_RETURN(match); } @@ -9399,10 +9446,7 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) if (!walk) DBUG_RETURN(TRUE); if (!walk->derived) - { target_tbl->table_name= walk->table_name; - target_tbl->table_name_length= walk->table_name_length; - } walk->updating= target_tbl->updating; walk->lock_type= target_tbl->lock_type; /* We can assume that tables to be deleted from are locked for write. */ @@ -9453,10 +9497,18 @@ bool update_precheck(THD *thd, TABLE_LIST *tables) bool delete_precheck(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("delete_precheck"); - if (check_one_table_access(thd, DELETE_ACL, tables)) - DBUG_RETURN(TRUE); - /* Set privilege for the WHERE clause */ - tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); + if (tables->vers_conditions.is_set()) + { + if (check_one_table_access(thd, DELETE_HISTORY_ACL, tables)) + DBUG_RETURN(TRUE); + } + else + { + if (check_one_table_access(thd, DELETE_ACL, tables)) + DBUG_RETURN(TRUE); + /* Set privilege for the WHERE clause */ + tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); + } DBUG_RETURN(FALSE); } @@ -9560,7 +9612,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, if (lex->create_info.or_replace() && !lex->tmp_table()) want_priv|= DROP_ACL; - if (check_access(thd, want_priv, create_table->db, + if (check_access(thd, want_priv, create_table->db.str, &create_table->grant.privilege, &create_table->grant.m_internal, 0, 0)) @@ -9626,7 +9678,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, goto err; } - if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, create_table->db)) + if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, + create_table->db.str)) goto err; error= FALSE; @@ -9713,7 +9766,7 @@ void get_default_definer(THD *thd, LEX_USER *definer, bool role) if (role) { definer->user.str= const_cast<char*>(sctx->priv_role); - definer->host= empty_lex_str; + definer->host= empty_clex_str; } else { @@ -9742,7 +9795,7 @@ LEX_USER *create_default_definer(THD *thd, bool role) { LEX_USER *definer; - if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + if (unlikely(! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))) return 0; thd->get_definer(definer, role); @@ -9770,13 +9823,14 @@ LEX_USER *create_default_definer(THD *thd, bool role) - On error, return 0. */ -LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) +LEX_USER *create_definer(THD *thd, LEX_CSTRING *user_name, + LEX_CSTRING *host_name) { LEX_USER *definer; /* Create and initialize. */ - if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + if (unlikely(!(definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))) return 0; definer->user= *user_name; @@ -9804,8 +9858,8 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name) The function is not used in existing code but can be useful later? */ -bool check_string_byte_length(LEX_STRING *str, uint err_msg, - uint max_byte_length) +bool check_string_byte_length(const LEX_CSTRING *str, uint err_msg, + size_t max_byte_length) { if (str->length <= max_byte_length) return FALSE; @@ -9834,12 +9888,13 @@ bool check_string_byte_length(LEX_STRING *str, uint err_msg, */ -bool check_string_char_length(LEX_STRING *str, uint err_msg, - uint max_char_length, CHARSET_INFO *cs, +bool check_string_char_length(const LEX_CSTRING *str, uint err_msg, + size_t max_char_length, CHARSET_INFO *cs, bool no_error) { Well_formed_prefix prefix(cs, str->str, str->length, max_char_length); - if (!prefix.well_formed_error_pos() && str->length == prefix.length()) + if (likely(!prefix.well_formed_error_pos() && + str->length == prefix.length())) return FALSE; if (!no_error) @@ -9853,7 +9908,7 @@ bool check_string_char_length(LEX_STRING *str, uint err_msg, } -bool check_ident_length(LEX_STRING *ident) +bool check_ident_length(const LEX_CSTRING *ident) { if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1)) { @@ -9879,7 +9934,7 @@ extern "C" { int path_starts_from_data_home_dir(const char *path) { - int dir_len= strlen(path); + size_t dir_len= strlen(path); DBUG_ENTER("path_starts_from_data_home_dir"); if (mysql_unpacked_real_data_home_len<= dir_len) @@ -9963,7 +10018,7 @@ int error_if_data_home_dir(const char *path, const char *what) has invalid symbols */ -bool check_host_name(LEX_STRING *str) +bool check_host_name(LEX_CSTRING *str) { const char *name= str->str; const char *end= str->str + str->length; @@ -9986,6 +10041,7 @@ bool check_host_name(LEX_STRING *str) extern int MYSQLparse(THD *thd); // from sql_yacc.cc +extern int ORAparse(THD *thd); // from sql_yacc_ora.cc /** @@ -10029,8 +10085,7 @@ bool parse_sql(THD *thd, Parser_state *parser_state, /* Start Digest */ parser_state->m_digest_psi= MYSQL_DIGEST_START(thd->m_statement_psi); - if (parser_state->m_input.m_compute_digest || - (parser_state->m_digest_psi != NULL)) + if (parser_state->m_digest_psi != NULL) { /* If either: @@ -10045,7 +10100,10 @@ bool parse_sql(THD *thd, Parser_state *parser_state, /* Parse the query. */ - bool mysql_parse_status= MYSQLparse(thd) != 0; + bool mysql_parse_status= + ((thd->variables.sql_mode & MODE_ORACLE) ? + ORAparse(thd) : + MYSQLparse(thd)) != 0; /* Check that if MYSQLparse() failed either thd->is_error() is set, or an |