diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 120 |
1 files changed, 93 insertions, 27 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1ce0308d251..5e45c06996e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,6 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. +/* + Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2008-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +13,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #define MYSQL_LEX 1 #include "mysql_priv.h" @@ -28,6 +31,7 @@ #include "events.h" #include "sql_trigger.h" #include "debug_sync.h" +#include <rpl_mi.h> #ifdef WITH_ARIA_STORAGE_ENGINE #include "../storage/maria/ha_maria.h" @@ -502,6 +506,8 @@ static void handle_bootstrap_impl(THD *thd) query= (char *) thd->memdup_w_gap(buff, length + 1, thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); + size_t db_len= 0; + memcpy(query + length + 1, (char *) &db_len, sizeof(size_t)); thd->set_query(query, length); DBUG_PRINT("query",("%-.4096s", thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) @@ -1448,6 +1454,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_REFRESH: { int not_used; + + /* + Initialize thd->lex since it's used in many base functions, such as + open_tables(). Otherwise, it remains unitialized and may cause crash + during execution of COM_REFRESH. + */ + lex_start(thd); + status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]); ulong options= (ulong) (uchar) packet[0]; if (check_global_access(thd,RELOAD_ACL)) @@ -1907,13 +1921,30 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length) pos--; packet_length--; } - /* We must allocate some extra memory for query cache */ + /* We must allocate some extra memory for query cache + + The query buffer layout is: + buffer :== + <statement> The input statement(s) + '\0' Terminating null char (1 byte) + <length> Length of following current database name (size_t) + <db_name> Name of current database + <flags> Flags struct + */ if (! (query= (char*) thd->memdup_w_gap(packet, packet_length, - 1 + thd->db_length + + 1 + sizeof(size_t) + thd->db_length + QUERY_CACHE_FLAGS_SIZE))) return TRUE; query[packet_length]= '\0'; + /* + Space to hold the name of the current database is allocated. We + also store this length, in case current database is changed during + execution. We might need to reallocate the 'query' buffer + */ + char *len_pos = (query + packet_length + 1); + memcpy(len_pos, (char *) &thd->db_length, sizeof(size_t)); + thd->set_query(query, packet_length); /* Reclaim some memory */ @@ -2611,6 +2642,12 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; #endif /* + If no engine type was given, work out the default now + rather than at parse-time. + */ + if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) + create_info.db_type= ha_default_handlerton(thd); + /* If we are using SET CHARSET without DEFAULT, add an implicit DEFAULT to not confuse old users. (This may change). */ @@ -3964,8 +4001,7 @@ end_with_restore_list: hostname_requires_resolving(user->host.str)) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_HOSTNAME_WONT_WORK, - ER(ER_WARN_HOSTNAME_WONT_WORK), - user->host.str); + ER(ER_WARN_HOSTNAME_WONT_WORK)); // Are we trying to change a password of another user DBUG_ASSERT(user->host.str != 0); if (strcmp(thd->security_ctx->user, user->user.str) || @@ -5957,7 +5993,7 @@ mysql_new_select(LEX *lex, bool move_down) lex->nest_level++; if (lex->nest_level > (int) MAX_SELECT_NESTING) { - my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING); + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); DBUG_RETURN(1); } select_lex->nest_level= lex->nest_level; @@ -7066,9 +7102,9 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } #ifdef HAVE_REPLICATION int rotate_error= 0; - pthread_mutex_lock(&LOCK_active_mi); + pthread_mutex_lock(&active_mi->data_lock); rotate_error= rotate_relay_log(active_mi); - pthread_mutex_unlock(&LOCK_active_mi); + pthread_mutex_unlock(&active_mi->data_lock); if (rotate_error) *write_to_binlog= -1; #endif @@ -7079,7 +7115,14 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (ha_flush_logs(NULL)) result=1; if (flush_error_log()) - result=1; + { + /* + When flush_error_log() failed, my_error() has not been called. + So, we have to do it here to keep the protocol. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0)); + result= 1; + } } if (((options & (REFRESH_SLOW_QUERY_LOG | REFRESH_LOG)) == REFRESH_SLOW_QUERY_LOG)) @@ -7135,7 +7178,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, return 1; // Killed if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? FALSE : TRUE, TRUE)) - result= 1; + { + /* + NOTE: my_error() has been already called by reopen_tables() within + close_cached_tables(). + */ + result= 1; + } if (make_global_read_lock_block_commit(thd)) // Killed { @@ -7148,7 +7197,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? FALSE : TRUE, FALSE)) + { + /* + NOTE: my_error() has been already called by reopen_tables() within + close_cached_tables(). + */ result= 1; + } } my_dbopt_cleanup(); } @@ -7165,26 +7220,33 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; if (reset_master(thd)) { - result=1; + /* NOTE: my_error() has been already called by reset_master(). */ + result= 1; } } #endif #ifdef OPENSSL - if (options & REFRESH_DES_KEY_FILE) - { - if (des_key_file && load_des_key_file(des_key_file)) - result= 1; - } + if (options & REFRESH_DES_KEY_FILE) + { + if (des_key_file && load_des_key_file(des_key_file)) + { + /* NOTE: my_error() has been already called by load_des_key_file(). */ + result= 1; + } + } #endif #ifdef HAVE_REPLICATION - if (options & REFRESH_SLAVE) - { - tmp_write_to_binlog= 0; - pthread_mutex_lock(&LOCK_active_mi); - if (reset_slave(thd, active_mi)) - result=1; - pthread_mutex_unlock(&LOCK_active_mi); - } + if (options & REFRESH_SLAVE) + { + tmp_write_to_binlog= 0; + pthread_mutex_lock(&LOCK_active_mi); + if (reset_slave(thd, active_mi)) + { + /* NOTE: my_error() has been already called by reset_slave(). */ + result= 1; + } + pthread_mutex_unlock(&LOCK_active_mi); + } #endif if (options & REFRESH_USER_RESOURCES) reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ @@ -8115,10 +8177,14 @@ bool parse_sql(THD *thd, mysql_parse_status= MYSQLparse(thd) != 0; - /* Check that if MYSQLparse() failed, thd->is_error() is set. */ + /* + Check that if MYSQLparse() failed, thd->is_error() is set (unless + we have an error handler installed, which might have silenced error). + */ DBUG_ASSERT(!mysql_parse_status || - (mysql_parse_status && thd->is_error())); + thd->is_error() || + thd->get_internal_handler()); /* Reset parser state. */ |