summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc120
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. */