summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2012-08-22 11:40:39 +0200
committerSergei Golubchik <sergii@pisem.net>2012-08-22 11:40:39 +0200
commitcefc30b1663114930439e03dec245604bc904604 (patch)
tree83a4479fe38adb24e478dde743856f04d65fa801 /sql
parent34f2f8ea41726d98e50752ff3453ebde70912c35 (diff)
parent171355077501da7ddd32778ab3ebe77c5f7ce7da (diff)
downloadmariadb-git-cefc30b1663114930439e03dec245604bc904604.tar.gz
merge with MySQL 5.1.65
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am1
-rwxr-xr-xsql/event_scheduler.cc4
-rw-r--r--sql/field.cc11
-rw-r--r--sql/handler.cc13
-rw-r--r--sql/item.cc2
-rw-r--r--sql/log.cc5
-rw-r--r--sql/log.h11
-rw-r--r--sql/log_event.cc139
-rw-r--r--sql/log_event.h28
-rw-r--r--sql/mem_root_array.h175
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/mysqld.cc38
-rw-r--r--sql/protocol.cc6
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/rpl_rli.h35
-rw-r--r--sql/rpl_utility.cc61
-rw-r--r--sql/rpl_utility.h18
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/slave.cc25
-rw-r--r--sql/sql_base.cc36
-rw-r--r--sql/sql_class.cc21
-rw-r--r--sql/sql_class.h21
-rw-r--r--sql/sql_lex.cc22
-rw-r--r--sql/sql_lex.h16
-rw-r--r--sql/sql_parse.cc12
-rw-r--r--sql/sql_prepare.cc8
-rw-r--r--sql/sql_profile.cc8
-rw-r--r--sql/sql_repl.cc11
-rw-r--r--sql/sql_select.cc11
-rw-r--r--sql/sql_show.cc64
-rw-r--r--sql/sql_yacc.yy18
31 files changed, 713 insertions, 114 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 5b125be2eb5..92fcc4cdb6b 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -73,6 +73,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
+ mem_root_array.h \
sql_array.h sql_cursor.h events.h scheduler.h \
event_db_repository.h event_queue.h \
sql_plugin.h authors.h event_parse_data.h \
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index fb66a50ee7f..9f3bba3e896 100755
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -640,13 +640,13 @@ Event_scheduler::stop()
DBUG_PRINT("info", ("Scheduler thread has id %lu",
scheduler_thd->thread_id));
/* Lock from delete */
- pthread_mutex_lock(&scheduler_thd->LOCK_thd_data);
+ pthread_mutex_lock(&scheduler_thd->LOCK_thd_kill);
/* This will wake up the thread if it waits on Queue's conditional */
sql_print_information("Event Scheduler: Killing the scheduler thread, "
"thread id %lu",
scheduler_thd->thread_id);
scheduler_thd->awake(THD::KILL_CONNECTION);
- pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data);
+ pthread_mutex_unlock(&scheduler_thd->LOCK_thd_kill);
/* thd could be 0x0, when shutting down */
sql_print_information("Event Scheduler: "
diff --git a/sql/field.cc b/sql/field.cc
index a8bb59ca417..278ba83cc81 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -10236,6 +10236,17 @@ Create_field::Create_field(Field *old_field,Field *orig_field)
geom_type= ((Field_geom*)old_field)->geom_type;
break;
#endif
+ case MYSQL_TYPE_YEAR:
+ if (length != 4)
+ {
+ char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
+ my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length);
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER(ER_WARN_DEPRECATED_SYNTAX),
+ buff, "YEAR(4)");
+ }
+ break;
default:
break;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 234420b64a8..e56bb93caab 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2416,8 +2416,19 @@ int handler::update_auto_increment()
reservation means potentially losing unused values).
Note that in prelocked mode no estimation is given.
*/
+
if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0))
nb_desired_values= estimation_rows_to_insert;
+ else if ((auto_inc_intervals_count == 0) &&
+ (thd->lex->many_values.elements > 0))
+ {
+ /*
+ For multi-row inserts, if the bulk inserts cannot be started, the
+ handler::estimation_rows_to_insert will not be set. But we still
+ want to reserve the autoinc values.
+ */
+ nb_desired_values= thd->lex->many_values.elements;
+ }
else /* go with the increasing defaults */
{
/* avoid overflow in formula, with this if() */
@@ -4757,6 +4768,8 @@ int handler::ha_write_row(uchar *buf)
DBUG_RETURN(error);
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
DBUG_RETURN(error); /* purecov: inspected */
+
+ DEBUG_SYNC_C("ha_write_row_end");
DBUG_RETURN(0);
}
diff --git a/sql/item.cc b/sql/item.cc
index c2e208fe10f..7ca51157e9c 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -6010,7 +6010,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (from_field != not_found_field)
{
Item_field* fld;
- if (!(fld= new Item_field(from_field)))
+ if (!(fld= new Item_field(thd, last_checked_context, from_field)))
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
diff --git a/sql/log.cc b/sql/log.cc
index c74e8bc9233..732ce6326fc 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2423,7 +2423,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
{
end= strxmov(buff, "# administrator command: ", NullS);
buff_len= (ulong) (end - buff);
- my_b_write(&log_file, (uchar*) buff, buff_len);
+ DBUG_EXECUTE_IF("simulate_slow_log_write_error",
+ {DBUG_SET("+d,simulate_file_write_error");});
+ if(my_b_write(&log_file, (uchar*) buff, buff_len))
+ tmp_errno= errno;
}
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
my_b_write(&log_file, (uchar*) ";\n",2) ||
diff --git a/sql/log.h b/sql/log.h
index 361ad0f2a91..f42ef514307 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2005, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2005, 2012, Oracle and/or its affiliates.
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
@@ -130,6 +130,11 @@ extern TC_LOG_DUMMY tc_log_dummy;
class Relay_log_info;
+/*
+ Note that we destroy the lock mutex in the desctructor here.
+ This means that object instances cannot be destroyed/go out of scope,
+ until we have reset thd->current_linfo to NULL;
+ */
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];
@@ -289,8 +294,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
int new_file_impl(bool need_lock);
public:
- MYSQL_LOG::generate_name;
- MYSQL_LOG::is_open;
+ using MYSQL_LOG::generate_name;
+ using MYSQL_LOG::is_open;
/* This is relay log */
bool is_relay_log;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 2ca1721a7ab..06722bdbeca 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1121,7 +1121,7 @@ failed my_b_read"));
Log_event *res= 0;
#ifndef max_allowed_packet
THD *thd=current_thd;
- uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0;
+ uint max_allowed_packet= thd ? slave_max_allowed_packet:~(ulong)0;
#endif
if (data_len > max_allowed_packet)
@@ -2834,23 +2834,40 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
pos= (const uchar*) end; // Break loop
}
}
-
+
+ /**
+ Layout for the data buffer is as follows
+ +--------+-----------+------+------+---------+----+-------+
+ | catlog | time_zone | user | host | db name | \0 | Query |
+ +--------+-----------+------+------+---------+----+-------+
+
+ To support the query cache we append the following buffer to the above
+ +-------+----------------------------------------+-------+
+ |db len | uninitiatlized space of size of db len | FLAGS |
+ +-------+----------------------------------------+-------+
+
+ The area of buffer starting from Query field all the way to the end belongs
+ to the Query buffer and its structure is described in alloc_query() in
+ sql_parse.cc
+ */
+
#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE)
- if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 +
- time_zone_len + 1 +
- data_len + 1 +
- QUERY_CACHE_FLAGS_SIZE +
- user.length + 1 +
- host.length + 1 +
- db_len + 1,
- MYF(MY_WME))))
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1
+ + time_zone_len + 1
+ + user.length + 1
+ + host.length + 1
+ + data_len + 1
+ + sizeof(size_t)//for db_len
+ + db_len + 1
+ + QUERY_CACHE_FLAGS_SIZE,
+ MYF(MY_WME))))
#else
- if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 +
- time_zone_len + 1 +
- data_len + 1 +
- user.length + 1 +
- host.length + 1,
- MYF(MY_WME))))
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1
+ + time_zone_len + 1
+ + user.length + 1
+ + host.length + 1
+ + data_len + 1,
+ MYF(MY_WME))))
#endif
DBUG_VOID_RETURN;
if (catalog_len) // If catalog is given
@@ -2890,6 +2907,14 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
db= (char *)start;
query= (char *)(start + db_len + 1);
q_len= data_len - db_len -1;
+ /**
+ Append the db length at the end of the buffer. This will be used by
+ Query_cache::send_result_to_client() in case the query cache is On.
+ */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE)
+ size_t db_length= (size_t)db_len;
+ memcpy(start + data_len + 1, &db_length, sizeof(size_t));
+#endif
DBUG_VOID_RETURN;
}
@@ -3071,6 +3096,12 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file);
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_write().
+ */
+ DBUG_EXECUTE_IF ("simulate_file_write_error",
+ {(&cache)->write_pos= (&cache)->write_end- 500;});
print_query_header(&cache, print_event_info);
my_b_write(&cache, (uchar*) query, q_len);
my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
@@ -5269,11 +5300,12 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#endif
+#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
+
/*
Intvar_log_event::do_apply_event()
*/
-#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
{
/*
@@ -5282,6 +5314,9 @@ int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
+ if (rli->deferred_events_collecting)
+ return rli->deferred_events->add(this);
+
switch (type) {
case LAST_INSERT_ID_EVENT:
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
@@ -5387,6 +5422,9 @@ int Rand_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
+ if (rli->deferred_events_collecting)
+ return rli->deferred_events->add(this);
+
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
return 0;
@@ -5413,6 +5451,29 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli)
return continue_group(rli);
}
+/**
+ Exec deferred Int-, Rand- and User- var events prefixing
+ a Query-log-event event.
+
+ @param thd THD handle
+
+ @return false on success, true if a failure in an event applying occurred.
+*/
+bool slave_execute_deferred_events(THD *thd)
+{
+ bool res= false;
+ Relay_log_info *rli= thd->rli_slave;
+
+ DBUG_ASSERT(rli && (!rli->deferred_events_collecting || rli->deferred_events));
+
+ if (!rli->deferred_events_collecting || rli->deferred_events->is_empty())
+ return res;
+
+ res= rli->deferred_events->execute(rli);
+
+ return res;
+}
+
#endif /* !MYSQL_CLIENT */
@@ -5593,6 +5654,9 @@ User_var_log_event::
User_var_log_event(const char* buf,
const Format_description_log_event* description_event)
:Log_event(buf, description_event)
+#ifndef MYSQL_CLIENT
+ , deferred(false)
+#endif
{
/* The Post-Header is empty. The Variable Data part begins immediately. */
buf+= description_event->common_header_len +
@@ -5800,6 +5864,13 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
{
Item *it= 0;
CHARSET_INFO *charset;
+
+ if (rli->deferred_events_collecting)
+ {
+ set_deferred();
+ return rli->deferred_events->add(this);
+ }
+
if (!(charset= get_charset(charset_number, MYF(MY_WME))))
return 1;
LEX_STRING user_var_name;
@@ -5851,7 +5922,8 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
return 0;
}
}
- Item_func_set_user_var e(user_var_name, it);
+
+ Item_func_set_user_var *e= new Item_func_set_user_var(user_var_name, it);
/*
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
@@ -5860,7 +5932,7 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
crash the server, so if fix fields fails, we just return with an
error.
*/
- if (e.fix_fields(thd, 0))
+ if (e->fix_fields(thd, 0))
return 1;
/*
@@ -5868,8 +5940,9 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
a single record and with a single column. Thus, like
a column value, it could always have IMPLICIT derivation.
*/
- e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0);
- free_root(thd->mem_root,0);
+ e->update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0);
+ if (!is_deferred())
+ free_root(thd->mem_root,0);
return 0;
}
@@ -6263,11 +6336,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info
{
Load_log_event::print(file, print_event_info,
!check_fname_outside_temp_buf());
- /*
- That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
- SHOW BINLOG EVENTS we don't.
- */
- my_b_printf(&cache, "#");
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_create_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
+ /*
+ That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
+ SHOW BINLOG EVENTS we don't.
+ */
+ my_b_printf(&cache, "#");
}
my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len);
@@ -6944,6 +7024,13 @@ void Execute_load_query_log_event::print(FILE* file,
Write_on_release_cache cache(&print_event_info->head_cache, file);
print_query_header(&cache, print_event_info);
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
if (local_fname)
{
diff --git a/sql/log_event.h b/sql/log_event.h
index 645585c8ccb..a3c0eccd85a 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -275,6 +275,13 @@ struct sql_ex_info
MAX_SIZE_LOG_EVENT_STATUS + /* status */ \
NAME_LEN + 1)
+/*
+ The new option is added to handle large packets that are sent from the master
+ to the slave. It is used to increase the thd(max_allowed) for both the
+ DUMP thread on the master and the SQL/IO thread on the slave.
+*/
+#define MAX_MAX_ALLOWED_PACKET 1024*1024*1024
+
/*
Event header offsets;
these point to places inside the fixed header.
@@ -2476,11 +2483,13 @@ public:
uint charset_number;
bool is_null;
#ifndef MYSQL_CLIENT
+ bool deferred;
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
char *val_arg, ulong val_len_arg, Item_result type_arg,
uint charset_number_arg)
:Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
- val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
+ val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg),
+ deferred(false)
{ is_null= !val; }
void pack_info(Protocol* protocol);
#else
@@ -2493,6 +2502,13 @@ public:
Log_event_type get_type_code() { return USER_VAR_EVENT;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file);
+ /*
+ Getter and setter for deferred User-event.
+ Returns true if the event is not applied directly
+ and which case the applier adjusts execution path.
+ */
+ bool is_deferred() { return deferred; }
+ void set_deferred() { deferred= val; }
#endif
bool is_valid() const { return 1; }
@@ -3965,6 +3981,16 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
const char **group_relay_log_name,
ulonglong *relay_log_pos);
+#ifndef MYSQL_CLIENT
+/**
+ The function is called by slave applier in case there are
+ active table filtering rules to force gathering events associated
+ with Query-log-event into an array to execute
+ them once the fate of the Query is determined for execution.
+*/
+bool slave_execute_deferred_events(THD *thd);
+#endif
+
/**
@} (end of group Replication)
*/
diff --git a/sql/mem_root_array.h b/sql/mem_root_array.h
new file mode 100644
index 00000000000..5ce4dcb584d
--- /dev/null
+++ b/sql/mem_root_array.h
@@ -0,0 +1,175 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+ 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 */
+
+
+#ifndef MEM_ROOT_ARRAY_INCLUDED
+#define MEM_ROOT_ARRAY_INCLUDED
+
+#include <my_alloc.h>
+
+/**
+ A typesafe replacement for DYNAMIC_ARRAY.
+ We use MEM_ROOT for allocating storage, rather than the C++ heap.
+ The interface is chosen to be similar to std::vector.
+
+ @remark
+ Unlike DYNAMIC_ARRAY, elements are properly copied
+ (rather than memcpy()d) if the underlying array needs to be expanded.
+
+ @remark
+ Depending on has_trivial_destructor, we destroy objects which are
+ removed from the array (including when the array object itself is destroyed).
+
+ @remark
+ Note that MEM_ROOT has no facility for reusing free space,
+ so don't use this if multiple re-expansions are likely to happen.
+
+ @param Element_type The type of the elements of the container.
+ Elements must be copyable.
+ @param has_trivial_destructor If true, we don't destroy elements.
+ We could have used type traits to determine this.
+ __has_trivial_destructor is supported by some (but not all)
+ compilers we use.
+*/
+template<typename Element_type, bool has_trivial_destructor>
+class Mem_root_array
+{
+public:
+ Mem_root_array(MEM_ROOT *root)
+ : m_root(root), m_array(NULL), m_size(0), m_capacity(0)
+ {
+ DBUG_ASSERT(m_root != NULL);
+ }
+
+ ~Mem_root_array()
+ {
+ clear();
+ }
+
+ Element_type &at(size_t n)
+ {
+ DBUG_ASSERT(n < size());
+ return m_array[n];
+ }
+
+ const Element_type &at(size_t n) const
+ {
+ DBUG_ASSERT(n < size());
+ return m_array[n];
+ }
+
+ // Returns a pointer to the first element in the array.
+ Element_type *begin() { return &m_array[0]; }
+
+ // Returns a pointer to the past-the-end element in the array.
+ Element_type *end() { return &m_array[size()]; }
+
+ // Erases all of the elements.
+ void clear()
+ {
+ if (!empty())
+ chop(0);
+ }
+
+ /*
+ Chops the tail off the array, erasing all tail elements.
+ @param pos Index of first element to erase.
+ */
+ void chop(const size_t pos)
+ {
+ DBUG_ASSERT(pos < m_size);
+ if (!has_trivial_destructor)
+ {
+ for (size_t ix= pos; ix < m_size; ++ix)
+ {
+ Element_type *p= &m_array[ix];
+ p->~Element_type(); // Destroy discarded element.
+ }
+ }
+ m_size= pos;
+ }
+
+ /*
+ Reserves space for array elements.
+ Copies over existing elements, in case we are re-expanding the array.
+
+ @param n number of elements.
+ @retval true if out-of-memory, false otherwise.
+ */
+ bool reserve(size_t n)
+ {
+ if (n <= m_capacity)
+ return false;
+
+ void *mem= alloc_root(m_root, n * element_size());
+ if (!mem)
+ return true;
+ Element_type *array= static_cast<Element_type*>(mem);
+
+ // Copy all the existing elements into the new array.
+ for (size_t ix= 0; ix < m_size; ++ix)
+ {
+ Element_type *new_p= &array[ix];
+ Element_type *old_p= &m_array[ix];
+ new (new_p) Element_type(*old_p); // Copy into new location.
+ if (!has_trivial_destructor)
+ old_p->~Element_type(); // Destroy the old element.
+ }
+
+ // Forget the old array.
+ m_array= array;
+ m_capacity= n;
+ return false;
+ }
+
+ /*
+ Adds a new element at the end of the array, after its current last
+ element. The content of this new element is initialized to a copy of
+ the input argument.
+
+ @param element Object to copy.
+ @retval true if out-of-memory, false otherwise.
+ */
+ bool push_back(const Element_type &element)
+ {
+ const size_t min_capacity= 20;
+ const size_t expansion_factor= 2;
+ if (0 == m_capacity && reserve(min_capacity))
+ return true;
+ if (m_size == m_capacity && reserve(m_capacity * expansion_factor))
+ return true;
+ Element_type *p= &m_array[m_size++];
+ new (p) Element_type(element);
+ return false;
+ }
+
+ size_t capacity() const { return m_capacity; }
+ size_t element_size() const { return sizeof(Element_type); }
+ bool empty() const { return size() == 0; }
+ size_t size() const { return m_size; }
+
+private:
+ MEM_ROOT *const m_root;
+ Element_type *m_array;
+ size_t m_size;
+ size_t m_capacity;
+
+ // Not (yet) implemented.
+ Mem_root_array(const Mem_root_array&);
+ Mem_root_array &operator=(const Mem_root_array&);
+};
+
+
+#endif // MEM_ROOT_ARRAY_INCLUDED
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 60abf5a2361..16fdaef2eae 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1971,6 +1971,7 @@ extern ulong slave_net_timeout, slave_trans_retries;
extern uint max_user_connections;
extern ulong what_to_log,flush_time;
extern ulong query_buff_size;
+extern ulong slave_max_allowed_packet;
extern ulong max_prepared_stmt_count, prepared_stmt_count;
extern ulong binlog_cache_size, open_files_limit;
extern ulonglong max_binlog_cache_size;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 3a7519991b2..629ffe26f2c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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
@@ -31,6 +31,7 @@
#include "events.h"
#include <waiting_threads.h>
#include "debug_sync.h"
+#include "log_event.h"
#include "../storage/myisam/ha_myisam.h"
@@ -581,6 +582,7 @@ static const char *slave_exec_mode_str= "STRICT";
ulong thread_cache_size=0, thread_pool_size= 0;
ulong binlog_cache_size=0;
ulonglong max_binlog_cache_size=0;
+ulong slave_max_allowed_packet= 0;
ulong query_cache_size=0;
ulong refresh_version; /* Increments on each reload */
query_id_t global_query_id;
@@ -5731,6 +5733,7 @@ enum options_mysqld
OPT_KEY_CACHE_DIVISION_LIMIT, OPT_KEY_CACHE_AGE_THRESHOLD,
OPT_LONG_QUERY_TIME,
OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
+ OPT_SLAVE_MAX_ALLOWED_PACKET,
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
@@ -6951,10 +6954,14 @@ thread is in the relay logs.",
&global_system_variables.max_allowed_packet,
&max_system_variables.max_allowed_packet, 0, GET_ULONG,
REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
+ {"slave_max_allowed_packet", OPT_SLAVE_MAX_ALLOWED_PACKET,
+ "The maximum packet length to sent successfully from the master to slave.",
+ &slave_max_allowed_packet, &slave_max_allowed_packet, 0, GET_ULONG,
+ REQUIRED_ARG, MAX_MAX_ALLOWED_PACKET, 1024, MAX_MAX_ALLOWED_PACKET, MALLOC_OVERHEAD, 1024, 0},
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
&max_binlog_cache_size, &max_binlog_cache_size, 0,
- GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0},
+ GET_ULL, REQUIRED_ARG, (longlong) ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0},
{"max_binlog_size", OPT_MAX_BINLOG_SIZE,
"Binary log will be rotated automatically when the size exceeds this "
"value. Will also apply to relay logs if max_relay_log_size is 0. "
@@ -6992,7 +6999,7 @@ thread is in the relay logs.",
"Joins that are probably going to read more than max_join_size records return an error.",
&global_system_variables.max_join_size,
&max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
- HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0},
+ (longlong) HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0},
{"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
"Max number of bytes in sorted records.",
&global_system_variables.max_length_for_sort_data,
@@ -7018,7 +7025,7 @@ thread is in the relay logs.",
"Limit assumed max number of seeks when looking up rows based on a key.",
&global_system_variables.max_seeks_for_key,
&max_system_variables.max_seeks_for_key, 0, GET_ULONG,
- REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0 },
+ REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 },
{"max_sort_length", OPT_MAX_SORT_LENGTH,
"The number of bytes to use when sorting BLOB or TEXT values (only the "
"first max_sort_length bytes of each value are used; the rest are ignored).",
@@ -7042,7 +7049,7 @@ thread is in the relay logs.",
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
"After this many write locks, allow some read locks to run in between.",
&max_write_lock_count, &max_write_lock_count, 0, GET_ULONG,
- REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, (longlong) ULONG_MAX, 1, ULONG_MAX, 0, 1, 0},
{"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT,
"Don't log queries which examine less than min_examined_row_limit rows to file.",
&global_system_variables.min_examined_row_limit,
@@ -7069,18 +7076,19 @@ thread is in the relay logs.",
&global_system_variables.myisam_max_extra_sort_file_size,
&max_system_variables.myisam_max_extra_sort_file_size,
0, GET_ULL, REQUIRED_ARG, (ulonglong) INT_MAX32,
- 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0},
+ 0, MAX_FILE_SIZE, 0, 1, 0},
{"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE,
"Don't use the fast sort index method to created index if the temporary "
"file would get bigger than this.",
&global_system_variables.myisam_max_sort_file_size,
&max_system_variables.myisam_max_sort_file_size, 0,
- GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE,
+ GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, MAX_FILE_SIZE,
0, 1024*1024, 0},
{"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE,
"Can be used to restrict the total memory used for memory mmaping of myisam files",
&myisam_mmap_size, &myisam_mmap_size, 0,
- GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0},
+ GET_ULL, REQUIRED_ARG, (longlong) SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX,
+ 0, 1, 0},
{"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS,
"Specifies whether several threads should be used when repairing MyISAM "
"tables. For values > 1, one thread is used per index. The value of 1 "
@@ -7093,7 +7101,7 @@ thread is in the relay logs.",
"or when creating indexes with CREATE INDEX or ALTER TABLE.",
&global_system_variables.myisam_sort_buff_size,
&max_system_variables.myisam_sort_buff_size, 0,
- GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, (longlong) ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0ULL, 0, 1, 0},
{"myisam_use_mmap", OPT_MYISAM_USE_MMAP,
"Use memory mapping for reading and writing MyISAM tables.",
&opt_myisam_use_mmap, &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG,
@@ -7201,7 +7209,7 @@ thread is in the relay logs.",
{"query_cache_size", OPT_QUERY_CACHE_SIZE,
"The memory allocated to store results from old queries.",
&query_cache_size, &query_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0},
+ REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1024, 0},
#ifdef HAVE_QUERY_CACHE
{"query_cache_type", OPT_QUERY_CACHE_TYPE,
"0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results "
@@ -7263,7 +7271,7 @@ thread is in the relay logs.",
"Maximum space to use for all relay logs.",
&relay_log_space_limit,
&relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L,
- (longlong) ULONG_MAX, 0, 1, 0},
+ ULONG_MAX, 0, 1, 0},
{"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL,
"Use compression on master/slave protocol.",
&opt_slave_compressed_protocol,
@@ -7278,7 +7286,7 @@ thread is in the relay logs.",
"it failed with a deadlock or elapsed lock wait timeout, "
"before giving up and stopping.",
&slave_trans_retries, &slave_trans_retries, 0,
- GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 10L, 0L, ULONG_MAX, 0, 1, 0},
#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), "
@@ -7289,8 +7297,8 @@ thread is in the relay logs.",
"Each thread that needs to do a sort allocates a buffer of this size.",
&global_system_variables.sortbuff_size,
&max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
- MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, (longlong) ULONG_MAX,
- MALLOC_OVERHEAD, 1, 0},
+ MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0ULL, MALLOC_OVERHEAD,
+ 1, 0},
{"sync-binlog", OPT_SYNC_BINLOG,
"Synchronously flush binary log to disk after every #th event. "
"Use 0 (default) to disable synchronous flushing.",
diff --git a/sql/protocol.cc b/sql/protocol.cc
index b3ae09a5755..c0e30f8d7ee 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008, 2011, Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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
@@ -683,6 +683,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
/* Store fixed length fields */
pos= (char*) local_packet->ptr()+local_packet->length();
*pos++= 12; // Length of packed fields
+ /* inject a NULL to test the client */
+ DBUG_EXECUTE_IF("poison_rs_fields", pos[-1]= 0xfb;);
if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
{
/* No conversion */
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index b56cef3913f..e2d008975ec 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -40,7 +40,9 @@ Relay_log_info::Relay_log_info()
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0),
tables_to_lock(0), tables_to_lock_count(0),
- last_event_start_time(0), m_flags(0)
+ last_event_start_time(0),
+ deferred_events(NULL),
+ m_flags(0)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index f82d0901d79..4d0b6c39d19 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -369,6 +369,41 @@ public:
*/
time_t last_event_start_time;
+ /*
+ A container to hold on Intvar-, Rand-, Uservar- log-events in case
+ the slave is configured with table filtering rules.
+ The withhold events are executed when their parent Query destiny is
+ determined for execution as well.
+ */
+ Deferred_log_events *deferred_events;
+
+ /*
+ State of the container: true stands for IRU events gathering,
+ false does for execution, either deferred or direct.
+ */
+ bool deferred_events_collecting;
+
+ /*
+ Returns true if the argument event resides in the containter;
+ more specifically, the checking is done against the last added event.
+ */
+ bool is_deferred_event(Log_event * ev)
+ {
+ return deferred_events_collecting ? deferred_events->is_last(ev) : false;
+ };
+ /* The general cleanup that slave applier may need at the end of query. */
+ inline void cleanup_after_query()
+ {
+ if (deferred_events)
+ deferred_events->rewind();
+ };
+ /* The general cleanup that slave applier may need at the end of session. */
+ void cleanup_after_session()
+ {
+ if (deferred_events)
+ delete deferred_events;
+ };
+
/**
Helper function to do after statement completion.
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index d304d5fbd6a..dad2309981f 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -226,3 +226,64 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table)
return error;
}
+
+#ifndef MYSQL_CLIENT
+Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
+{
+ my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16);
+}
+
+Deferred_log_events::~Deferred_log_events()
+{
+ delete_dynamic(&array);
+}
+
+int Deferred_log_events::add(Log_event *ev)
+{
+ last_added= ev;
+ insert_dynamic(&array, (uchar*) &ev);
+ return 0;
+}
+
+bool Deferred_log_events::is_empty()
+{
+ return array.elements == 0;
+}
+
+bool Deferred_log_events::execute(Relay_log_info *rli)
+{
+ bool res= false;
+
+ DBUG_ASSERT(rli->deferred_events_collecting);
+
+ rli->deferred_events_collecting= false;
+ for (uint i= 0; !res && i < array.elements; i++)
+ {
+ Log_event *ev= (* (Log_event **)
+ dynamic_array_ptr(&array, i));
+ res= ev->apply_event(rli);
+ }
+ rli->deferred_events_collecting= true;
+ return res;
+}
+
+void Deferred_log_events::rewind()
+{
+ /*
+ Reset preceeding Query log event events which execution was
+ deferred because of slave side filtering.
+ */
+ if (!is_empty())
+ {
+ for (uint i= 0; i < array.elements; i++)
+ {
+ Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
+ delete ev;
+ }
+ if (array.elements > array.max_element)
+ freeze_size(&array);
+ reset_dynamic(&array);
+ }
+}
+
+#endif
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 701b9f3c5de..afe54f1dd28 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -290,6 +290,24 @@ namespace {
};
}
+
+class Deferred_log_events
+{
+private:
+ DYNAMIC_ARRAY array;
+ Log_event *last_added;
+
+public:
+ Deferred_log_events(Relay_log_info *rli);
+ ~Deferred_log_events();
+ /* queue for exection at Query-log-event time prior the Query */
+ int add(Log_event *ev);
+ bool is_empty();
+ bool execute(Relay_log_info *rli);
+ void rewind();
+ bool is_last(Log_event *ev) { return ev == last_added; };
+};
+
#endif
// NB. number of printed bit values is limited to sizeof(buf) - 1
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 40e26ea4930..6d12c45fc3c 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -396,6 +396,8 @@ static sys_var_const sys_lower_case_table_names(&vars,
static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet",
&SV::max_allowed_packet,
check_max_allowed_packet);
+static sys_var_long_ptr sys_slave_max_allowed_packet(&vars, "slave_max_allowed_packet",
+ &slave_max_allowed_packet);
static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size",
&max_binlog_cache_size);
static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size",
diff --git a/sql/slave.cc b/sql/slave.cc
index 41068ffa211..1a5dd9c4395 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -516,7 +516,7 @@ terminate_slave_thread(THD *thd,
int error __attribute__((unused));
DBUG_PRINT("loop", ("killing slave thread"));
- pthread_mutex_lock(&thd->LOCK_thd_data);
+ pthread_mutex_lock(&thd->LOCK_thd_kill);
#ifndef DONT_USE_THR_ALARM
/*
Error codes from pthread_kill are:
@@ -527,7 +527,7 @@ terminate_slave_thread(THD *thd,
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake(THD::NOT_KILLED);
- pthread_mutex_unlock(&thd->LOCK_thd_data);
+ pthread_mutex_unlock(&thd->LOCK_thd_kill);
/*
There is a small chance that slave thread might miss the first
@@ -1846,8 +1846,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
slave threads, since a replication event can become this much larger
than the corresponding packet (query) sent from client to master.
*/
- thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
- + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */
+ thd->variables.max_allowed_packet= slave_max_allowed_packet;
thd->slave_thread = 1;
thd->enable_slow_log= opt_log_slow_slave_statements;
thd->variables.log_slow_filter= global_system_variables.log_slow_filter;
@@ -2323,7 +2322,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
used to read info about the relay log's format; it will be deleted when
the SQL thread does not need it, i.e. when this thread terminates.
*/
- if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
+ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT &&
+ !rli->is_deferred_event(ev))
{
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
delete ev;
@@ -2593,6 +2593,7 @@ pthread_handler_t handle_slave_io(void *arg)
thread, since a replication event can become this much larger than
the corresponding packet (query) sent from client to master.
*/
+ thd->net.max_packet_size= slave_max_allowed_packet;
mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER;
}
else
@@ -2724,12 +2725,12 @@ reading event"))
switch (mysql_error_number) {
case CR_NET_PACKET_TOO_LARGE:
sql_print_error("\
-Log entry on master is longer than max_allowed_packet (%ld) on \
+Log entry on master is longer than slave_max_allowed_packet (%lu) on \
slave. If the entry is correct, restart the server with a higher value of \
-max_allowed_packet",
- thd->variables.max_allowed_packet);
+slave_max_allowed_packet",
+ slave_max_allowed_packet);
mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE,
- "%s", ER(ER_NET_PACKET_TOO_LARGE));
+ "%s", "Got a packet bigger than 'slave_max_allowed_packet' bytes");
goto err;
case ER_MASTER_FATAL_ERROR_READING_BINLOG:
mi->report(ERROR_LEVEL, ER_MASTER_FATAL_ERROR_READING_BINLOG,
@@ -2955,6 +2956,12 @@ pthread_handler_t handle_slave_sql(void *arg)
goto err;
}
thd->init_for_queries();
+ thd->rli_slave= rli;
+ if ((rli->deferred_events_collecting= rpl_filter->is_on()))
+ {
+ rli->deferred_events= new Deferred_log_events(rli);
+ }
+
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
pthread_mutex_lock(&LOCK_thread_count);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e895793f3c8..77ba3c5099c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -116,6 +116,8 @@ static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
bool send_refresh);
static bool
has_write_table_with_auto_increment(TABLE_LIST *tables);
+static bool
+has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables);
extern "C" uchar *table_cache_key(const uchar *record, size_t *length,
@@ -2210,6 +2212,8 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
*/
pthread_mutex_unlock(mutex);
+ DEBUG_SYNC(thd, "waiting_for_table_unlock");
+ DBUG_EXECUTE_IF("sleep_after_waiting_for_table", my_sleep(1000000););
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
@@ -5516,6 +5520,12 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
*(ptr++)= table->table;
}
+ if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables)
+ {
+ if (has_write_table_auto_increment_not_first_in_pk(tables))
+ thd->lex->set_stmt_unsafe();
+ }
+
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
if (thd->lex->requires_prelocking())
{
@@ -9130,6 +9140,32 @@ has_write_table_with_auto_increment(TABLE_LIST *tables)
return 0;
}
+/*
+ Tells if there is a table whose auto_increment column is a part
+ of a compound primary key while is not the first column in
+ the table definition.
+
+ @param tables Table list
+
+ @return true if the table exists, fais if does not.
+*/
+
+static bool
+has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ /* we must do preliminary checks as table->table may be NULL */
+ if (!table->placeholder() &&
+ table->table->found_next_number_field &&
+ (table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ && table->table->s->next_number_keypart != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
Open and lock system tables for read.
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 5d81c57d302..318875c6318 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -369,6 +369,7 @@ extern "C"
char *thd_security_context(THD *thd, char *buffer, unsigned int length,
unsigned int max_query_len)
{
+ DEBUG_SYNC(thd, "thd_security_context");
String str(buffer, length, &my_charset_latin1);
const Security_context *sctx= &thd->main_security_ctx;
char header[64];
@@ -607,7 +608,7 @@ Diagnostics_area::disable_status()
THD::THD()
:Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
/* statement id */ 0),
- Open_tables_state(refresh_version), rli_fake(0),
+ Open_tables_state(refresh_version), rli_fake(NULL), rli_slave(NULL),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
sql_log_bin_toplevel(false),
@@ -707,6 +708,7 @@ THD::THD()
active_vio = 0;
#endif
pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_thd_kill, MY_MUTEX_INIT_FAST);
/* Variables with default values */
proc_info="login";
@@ -1011,6 +1013,8 @@ THD::~THD()
/* Ensure that no one is using THD */
pthread_mutex_lock(&LOCK_thd_data);
pthread_mutex_unlock(&LOCK_thd_data);
+ pthread_mutex_lock(&LOCK_thd_kill);
+ pthread_mutex_unlock(&LOCK_thd_kill);
add_to_status(&global_status_var, &status_var);
/* Close connection */
@@ -1039,6 +1043,7 @@ THD::~THD()
#endif
mysys_var=0; // Safety (shouldn't be needed)
pthread_mutex_destroy(&LOCK_thd_data);
+ pthread_mutex_destroy(&LOCK_thd_kill);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
@@ -1048,6 +1053,8 @@ THD::~THD()
delete rli_fake;
rli_fake= NULL;
}
+ if (rli_slave)
+ rli_slave->cleanup_after_session();
#endif
free_root(&main_mem_root, MYF(0));
@@ -1123,9 +1130,11 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
void THD::awake(THD::killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
- DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
+ DBUG_PRINT("enter", ("this: 0x%lx thread_id=%lu killed_state=%d",
+ (long) this, thread_id, state_to_set));
THD_CHECK_SENTRY(this);
- safe_mutex_assert_owner(&LOCK_thd_data);
+ safe_mutex_assert_not_owner(&LOCK_thd_data);
+ safe_mutex_assert_owner(&LOCK_thd_kill);
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
@@ -1146,7 +1155,9 @@ void THD::awake(THD::killed_state state_to_set)
hack is not used.
*/
+ pthread_mutex_lock(&LOCK_thd_data);
close_active_vio();
+ pthread_mutex_unlock(&LOCK_thd_data);
}
#endif
}
@@ -1335,6 +1346,10 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= FALSE;
+#ifndef EMBEDDED_LIBRARY
+ if (rli_slave)
+ rli_slave->cleanup_after_query();
+#endif
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 40a5d61e433..fb4e13ad9c6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1312,6 +1312,8 @@ class THD :public Statement,
public:
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
+ /* Slave applier execution context */
+ Relay_log_info* rli_slave;
/*
Constant for THD::where initialization in the beginning of every query.
@@ -1362,11 +1364,23 @@ public:
Protects THD data accessed from other threads:
- thd->query and thd->query_length (used by SHOW ENGINE
INNODB STATUS and SHOW PROCESSLIST
- - thd->mysys_var (used by KILL statement and shutdown).
- Is locked when THD is deleted.
*/
pthread_mutex_t LOCK_thd_data;
+ /**
+ - Protects thd->mysys_var (used during KILL statement and shutdown).
+ - Is Locked when THD is deleted.
+
+ Note: This responsibility was earlier handled by LOCK_thd_data.
+ This lock is introduced to solve a deadlock issue waiting for
+ LOCK_thd_data. As this lock reduces responsibility of LOCK_thd_data
+ the deadlock issues is solved.
+ Caution: LOCK_thd_kill should not be taken while holding LOCK_thd_data.
+ THD::awake() currently takes LOCK_thd_data after holding
+ LOCK_thd_kill.
+ */
+ pthread_mutex_t LOCK_thd_kill;
+
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
@@ -2103,7 +2117,6 @@ public:
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
int send_explain_fields(select_result *result);
-#ifndef EMBEDDED_LIBRARY
/**
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
@@ -2119,9 +2132,9 @@ public:
is_slave_error= 0;
DBUG_VOID_RETURN;
}
+#ifndef EMBEDDED_LIBRARY
inline bool vio_ok() const { return net.vio != 0; }
#else
- void clear_error();
inline bool vio_ok() const { return true; }
#endif
/**
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index cbb3782114a..b95c3981310 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -305,6 +305,8 @@ void lex_start(THD *thd)
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
lex->select_lex.init_order();
lex->select_lex.group_list.empty();
+ if (lex->select_lex.group_list_ptrs)
+ lex->select_lex.group_list_ptrs->clear();
lex->describe= 0;
lex->subqueries= FALSE;
lex->context_analysis_only= 0;
@@ -1642,6 +1644,8 @@ void st_select_lex::init_select()
{
st_select_lex_node::init_select();
group_list.empty();
+ if (group_list_ptrs)
+ group_list_ptrs->clear();
type= db= 0;
having= 0;
table_join_options= 0;
@@ -2920,6 +2924,8 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
The passed WHERE and HAVING are to be saved for the future executions.
This function saves it, and returns a copy which can be thrashed during
this execution of the statement. By saving/thrashing here we mean only
+ We also save the chain of ORDER::next in group_list, in case
+ the list is modified by remove_const().
AND/OR trees.
The function also calls fix_prepare_info_in_table_list that saves all
ON expressions.
@@ -2931,6 +2937,19 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
if (!thd->stmt_arena->is_conventional() && first_execution)
{
first_execution= 0;
+ if (group_list.first)
+ {
+ if (!group_list_ptrs)
+ {
+ void *mem= thd->stmt_arena->alloc(sizeof(Group_list_ptrs));
+ group_list_ptrs= new (mem) Group_list_ptrs(thd->stmt_arena->mem_root);
+ }
+ group_list_ptrs->reserve(group_list.elements);
+ for (ORDER *order= group_list.first; order; order= order->next)
+ {
+ group_list_ptrs->push_back(order);
+ }
+ }
if (*conds)
{
thd->check_and_register_item_tree(&prep_where, conds);
@@ -3035,3 +3054,6 @@ bool st_lex::is_partition_management() const
alter_info.flags == ALTER_REORGANIZE_PARTITION));
}
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+template class Mem_root_array<ORDER*, true>;
+#endif
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3706d4c30ae..819cf41ec21 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -40,6 +40,7 @@ class Event_parse_data;
*/
#include "set_var.h"
+#include "mem_root_array.h"
#ifdef MYSQL_YACC
#define LEX_YYSTYPE void *
@@ -183,6 +184,7 @@ enum enum_drop_mode
};
typedef List<Item> List_item;
+typedef Mem_root_array<ORDER*, true> Group_list_ptrs;
/* SERVERS CACHE CHANGES */
typedef struct st_lex_server_options
@@ -590,7 +592,16 @@ public:
enum olap_type olap;
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
SQL_I_List<TABLE_LIST> table_list;
- SQL_I_List<ORDER> group_list; /* GROUP BY clause. */
+
+ /*
+ GROUP BY clause.
+ This list may be mutated during optimization (by remove_const()),
+ so for prepared statements, we keep a copy of the ORDER.next pointers in
+ group_list_ptrs, and re-establish the original list before each execution.
+ */
+ SQL_I_List<ORDER> group_list;
+ Group_list_ptrs *group_list_ptrs;
+
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list;
bool is_item_list_lookup;
@@ -778,7 +789,8 @@ public:
bool test_limit();
friend void lex_start(THD *thd);
- st_select_lex() : n_sum_items(0), n_child_sum_items(0) {}
+ st_select_lex() : group_list_ptrs(NULL), n_sum_items(0), n_child_sum_items(0)
+ {}
void make_empty_select()
{
init_query();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 64eb7645d03..e0e6a4a57d6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2307,6 +2307,11 @@ mysql_execute_command(THD *thd)
}
DBUG_RETURN(0);
}
+ /*
+ Execute deferred events first
+ */
+ if (slave_execute_deferred_events(thd))
+ DBUG_RETURN(-1);
}
else
{
@@ -3083,7 +3088,7 @@ end_with_restore_list:
goto error;
#else
{
- if (check_global_access(thd, SUPER_ACL))
+ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
res = show_binlogs(thd);
break;
@@ -7298,7 +7303,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
continue;
if (tmp->thread_id == id)
{
- pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
+ pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
break;
}
}
@@ -7326,12 +7331,13 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
if ((thd->security_ctx->master_access & SUPER_ACL) ||
thd->security_ctx->user_matches(tmp->security_ctx))
{
+ DEBUG_SYNC(thd, "kill_one_thread_before_kill");
tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0;
}
else
error=ER_KILL_DENIED_ERROR;
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ pthread_mutex_unlock(&tmp->LOCK_thd_kill);
}
DBUG_PRINT("exit", ("%d", error));
DBUG_RETURN(error);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 6aa119f7d71..7f5cbc5e99b 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2366,6 +2366,14 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
DBUG_ASSERT(sl->join == 0);
ORDER *order;
/* Fix GROUP list */
+ if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0)
+ {
+ for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix)
+ {
+ order= sl->group_list_ptrs->at(ix);
+ order->next= sl->group_list_ptrs->at(ix+1);
+ }
+ }
for (order= sl->group_list.first; order; order= order->next)
order->item= &order->item_ptr;
/* Fix ORDER list */
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index 116cdb91ef3..5bc91eff001 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2007, 2010, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+ Copyright (c) 2007, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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
@@ -82,8 +82,8 @@ ST_FIELD_INFO query_profile_statistics_info[]=
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
- int profile_options = thd->lex->profile_options;
- int fields_include_condition_truth_values[]= {
+ uint profile_options = thd->lex->profile_options;
+ uint fields_include_condition_truth_values[]= {
FALSE, /* Query_id */
FALSE, /* Seq */
TRUE, /* Status */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 7a09074f554..d84b8bbcd81 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -470,7 +470,7 @@ impossible position";
this larger than the corresponding packet (query) sent
from client to master.
*/
- thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER;
+ thd->variables.max_allowed_packet= MAX_MAX_ALLOWED_PACKET;
/*
We can set log_lock now, it does not move (it's a member of
@@ -1139,7 +1139,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
if (tmp->command == COM_BINLOG_DUMP &&
tmp->server_id == slave_server_id)
{
- pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
+ pthread_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
break;
}
}
@@ -1152,7 +1152,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
again. We just to do kill the thread ourselves.
*/
tmp->awake(THD::KILL_QUERY);
- pthread_mutex_unlock(&tmp->LOCK_thd_data);
+ pthread_mutex_unlock(&tmp->LOCK_thd_kill);
}
}
@@ -1460,6 +1460,8 @@ bool mysql_show_binlog_events(THD* thd)
IO_CACHE log;
File file = -1;
int old_max_allowed_packet= thd->variables.max_allowed_packet;
+ LOG_INFO linfo;
+
DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
@@ -1486,7 +1488,6 @@ bool mysql_show_binlog_events(THD* thd)
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
- LOG_INFO linfo;
Log_event* ev;
unit->set_limit(thd->lex->current_select);
@@ -1578,6 +1579,8 @@ bool mysql_show_binlog_events(THD* thd)
pthread_mutex_unlock(log_lock);
}
+ // Check that linfo is still on the function scope.
+ DEBUG_SYNC(thd, "after_show_binlog_events");
ret= FALSE;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 745e02e128a..3dc80bdef3b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -538,6 +538,8 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having)
{
+ Query_arena backup, *arena;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->where="having clause";
thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level;
@@ -546,6 +548,10 @@ JOIN::prepare(Item ***rref_pointer_array,
(having->fix_fields(thd, &having) ||
having->check_cols(1)));
select_lex->having_fix_field= 0;
+ select_lex->having= having;
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+
if (having_fix_rc || thd->is_error())
DBUG_RETURN(-1); /* purecov: inspected */
thd->lex->allow_sum_func= save_allow_sum_func;
@@ -12107,7 +12113,8 @@ int report_error(TABLE *table, int error)
Locking reads can legally return also these errors, do not
print them to the .err log
*/
- if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
+ if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT
+ && !table->in_use->killed)
sql_print_error("Got error %d when reading table '%s'",
error, table->s->path.str);
table->file->print_error(error,MYF(0));
@@ -14203,8 +14210,6 @@ check_reverse_order:
join_read_first:join_read_last;
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->covering_keys.is_set(best_key) && ! table->key_read)
- table->enable_keyread();
table->file->ha_index_or_rnd_end();
if (tab->join->select_options & SELECT_DESCRIBE)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 02505962347..f3e49b40811 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3232,39 +3232,44 @@ end:
static int fill_schema_table_names(THD *thd, TABLE *table,
LEX_STRING *db_name, LEX_STRING *table_name,
- bool with_i_schema)
+ bool with_i_schema,
+ bool need_table_type)
{
- if (with_i_schema)
+ /* Avoid opening FRM files if table type is not needed. */
+ if (need_table_type)
{
- table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
- system_charset_info);
- }
- else
- {
- enum legacy_db_type not_used;
- char path[FN_REFLEN + 1];
- (void) build_table_filename(path, sizeof(path) - 1, db_name->str,
- table_name->str, reg_ext, 0);
- switch (mysql_frm_type(thd, path, &not_used)) {
- case FRMTYPE_ERROR:
- table->field[3]->store(STRING_WITH_LEN("ERROR"),
- system_charset_info);
- break;
- case FRMTYPE_TABLE:
- table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
- system_charset_info);
- break;
- case FRMTYPE_VIEW:
- table->field[3]->store(STRING_WITH_LEN("VIEW"),
+ if (with_i_schema)
+ {
+ table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
system_charset_info);
- break;
- default:
- DBUG_ASSERT(0);
}
- if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
+ else
{
- thd->clear_error();
- return 0;
+ enum legacy_db_type not_used;
+ char path[FN_REFLEN + 1];
+ (void) build_table_filename(path, sizeof(path) - 1, db_name->str,
+ table_name->str, reg_ext, 0);
+ switch (mysql_frm_type(thd, path, &not_used)) {
+ case FRMTYPE_ERROR:
+ table->field[3]->store(STRING_WITH_LEN("ERROR"),
+ system_charset_info);
+ break;
+ case FRMTYPE_TABLE:
+ table->field[3]->store(STRING_WITH_LEN("BASE TABLE"),
+ system_charset_info);
+ break;
+ case FRMTYPE_VIEW:
+ table->field[3]->store(STRING_WITH_LEN("VIEW"),
+ system_charset_info);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
+ {
+ thd->clear_error();
+ return 0;
+ }
}
}
if (schema_table_store_record(thd, table))
@@ -3585,7 +3590,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (schema_table_idx == SCH_TABLE_NAMES)
{
if (fill_schema_table_names(thd, tables->table, db_name,
- table_name, with_i_schema))
+ table_name, with_i_schema,
+ lex->verbose))
continue;
}
else
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 37a963b4dfb..0dd36592539 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5060,7 +5060,23 @@ type:
$$= MYSQL_TYPE_VARCHAR;
}
| YEAR_SYM opt_field_length field_options
- { $$=MYSQL_TYPE_YEAR; }
+ {
+ if (Lex->length)
+ {
+ errno= 0;
+ ulong length= strtoul(Lex->length, NULL, 10);
+ if (errno == 0 && length <= MAX_FIELD_BLOBLENGTH && length != 4)
+ {
+ char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
+ my_snprintf(buff, sizeof(buff), "YEAR(%lu)", length);
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER(ER_WARN_DEPRECATED_SYNTAX),
+ buff, "YEAR(4)");
+ }
+ }
+ $$=MYSQL_TYPE_YEAR;
+ }
| DATE_SYM
{ $$=MYSQL_TYPE_DATE; }
| TIME_SYM