summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <mats@romeo.(none)>2007-02-23 14:59:48 +0100
committerunknown <mats@romeo.(none)>2007-02-23 14:59:48 +0100
commit5f7f3a5b817dee934750ff64b282dab498c39dfd (patch)
treefbf929e01e7b9b86acd45b34c0edfdeff4edac49 /sql
parenteadb2c2d950000f588246976b1d4adda4f224b6f (diff)
parentaf71cac0e44da5e1671c9f8fca2cd4b99f9eb02e (diff)
downloadmariadb-git-5f7f3a5b817dee934750ff64b282dab498c39dfd.tar.gz
Merge romeo.(none):/home/bkroot/mysql-5.1-new-rpl
into romeo.(none):/home/bk/b19033-mysql-5.1-new-rpl sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/log_event.h: Auto merged sql/slave.h: Auto merged sql/sql_insert.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc2
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc37
-rw-r--r--sql/log_event.h2
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/slave.cc64
-rw-r--r--sql/slave.h1
-rw-r--r--sql/sql_insert.cc50
8 files changed, 157 insertions, 5 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 3bea4e9c0fb..589f15d929e 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7213,7 +7213,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length))
return 2;
- if (copy_length < length)
+ if (from_end_pos < from + length)
{
report_data_too_long(this);
return 2;
diff --git a/sql/log.cc b/sql/log.cc
index ebeadf8ef03..5ec1826b991 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -4528,7 +4528,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
goto err;
if (using_heuristic_recover())
return 1;
- if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+ if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ea70c457f94..a326e226320 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2254,6 +2254,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf,
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
ST_SERVER_VER_LEN);
+ // prevent overrun if log is corrupted on disk
+ server_version[ST_SERVER_VER_LEN-1]= 0;
created= uint4korr(buf+ST_CREATED_OFFSET);
/* We use log_pos to mark if this was an artificial event or not */
artificial_event= (log_pos == 0);
@@ -2377,6 +2379,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
switch (binlog_ver) {
case 4: /* MySQL 5.0 */
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+ DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
+ strmov(server_version, "5.0.34"););
common_header_len= LOG_EVENT_HEADER_LEN;
number_of_event_types= LOG_EVENT_TYPES;
/* we'll catch my_malloc() error in is_valid() */
@@ -2467,6 +2471,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len= 0; /* will make is_valid() fail */
break;
}
+ calc_server_version_split();
}
@@ -2506,6 +2511,7 @@ Format_description_log_event(const char* buf,
post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
number_of_event_types*
sizeof(*post_header_len), MYF(0));
+ calc_server_version_split();
DBUG_VOID_RETURN;
}
@@ -2606,6 +2612,37 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
}
#endif
+
+/**
+ Splits the event's 'server_version' string into three numeric pieces stored
+ into 'server_version_split':
+ X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z}
+ X.Yabc -> {X,Y,0}
+ Xabc -> {X,0,0}
+ 'server_version_split' is then used for lookups to find if the server which
+ created this event has some known bug.
+*/
+void Format_description_log_event::calc_server_version_split()
+{
+ char *p= server_version, *r;
+ ulong number;
+ for (uint i= 0; i<=2; i++)
+ {
+ number= strtoul(p, &r, 10);
+ server_version_split[i]= (uchar)number;
+ DBUG_ASSERT(number < 256); // fit in uchar
+ p= r;
+ DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice
+ if (*r == '.')
+ p++; // skip the dot
+ }
+ DBUG_PRINT("info",("Format_description_log_event::server_version_split:"
+ " '%s' %d %d %d", server_version,
+ server_version_split[0],
+ server_version_split[1], server_version_split[2]));
+}
+
+
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
diff --git a/sql/log_event.h b/sql/log_event.h
index 6a9c8c3dc00..20a3ca1b97e 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1153,6 +1153,7 @@ public:
uint8 number_of_event_types;
/* The list of post-headers' lengthes */
uint8 *post_header_len;
+ uchar server_version_split[3];
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
@@ -1184,6 +1185,7 @@ public:
*/
return FORMAT_DESCRIPTION_HEADER_LEN;
}
+ void calc_server_version_split();
};
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index dd589c5bff9..26c91740c41 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3308,7 +3308,7 @@ server.");
(TC_LOG *) &tc_log_mmap) :
(TC_LOG *) &tc_log_dummy);
- if (tc_log->open(opt_bin_logname))
+ if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
unireg_abort(1);
@@ -7486,7 +7486,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_STANDALONE: /* Dummy option for NT */
break;
#endif
- /*
+ /*
The following change issues a deprecation warning if the slave
configuration is specified either in the my.cnf file or on
the command-line. See BUG#21490.
diff --git a/sql/slave.cc b/sql/slave.cc
index c21aec49e88..e51fca39fd8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3651,6 +3651,70 @@ end:
}
+/**
+ Detects, based on master's version (as found in the relay log), if master
+ has a certain bug.
+ @param rli RELAY_LOG_INFO which tells the master's version
+ @param bug_id Number of the bug as found in bugs.mysql.com
+ @return TRUE if master has the bug, FALSE if it does not.
+*/
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id)
+{
+ struct st_version_range_for_one_bug {
+ uint bug_id;
+ const uchar introduced_in[3]; // first version with bug
+ const uchar fixed_in[3]; // first version with fix
+ };
+ static struct st_version_range_for_one_bug versions_for_all_bugs[]=
+ {
+ {24432, { 5, 0, 24 }, { 5, 0, 36 } },
+ {24432, { 5, 1, 12 }, { 5, 1, 16 } }
+ };
+ const uchar *master_ver=
+ rli->relay_log.description_event_for_exec->server_version_split;
+
+ DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split) == 3);
+
+ for (uint i= 0;
+ i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++)
+ {
+ const uchar *introduced_in= versions_for_all_bugs[i].introduced_in,
+ *fixed_in= versions_for_all_bugs[i].fixed_in;
+ if ((versions_for_all_bugs[i].bug_id == bug_id) &&
+ (memcmp(introduced_in, master_ver, 3) <= 0) &&
+ (memcmp(fixed_in, master_ver, 3) > 0))
+ {
+ // a short message for SHOW SLAVE STATUS (message length constraints)
+ my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " so slave stops; check error log on slave"
+ " for more info", MYF(0), bug_id);
+ // a verbose message for the error log
+ slave_print_msg(ERROR_LEVEL, rli, ER_UNKNOWN_ERROR,
+ "According to the master's version ('%s'),"
+ " it is probable that master suffers from this bug:"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " and thus replicating the current binary log event"
+ " may make the slave's data become different from the"
+ " master's data."
+ " To take no risk, slave refuses to replicate"
+ " this event and stops."
+ " We recommend that all updates be stopped on the"
+ " master and slave, that the data of both be"
+ " manually synchronized,"
+ " that master's binary logs be deleted,"
+ " that master be upgraded to a version at least"
+ " equal to '%d.%d.%d'. Then replication can be"
+ " restarted.",
+ rli->relay_log.description_event_for_exec->server_version,
+ bug_id,
+ fixed_in[0], fixed_in[1], fixed_in[2]);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
diff --git a/sql/slave.h b/sql/slave.h
index 19ba4ad43ce..226f19fcd0c 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -161,6 +161,7 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
bool show_master_info(THD* thd, MASTER_INFO* mi);
bool show_binlog_info(THD* thd);
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id);
const char *print_slave_db_safe(const char *db);
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index d40b42f2d37..25f57698cc6 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -59,6 +59,7 @@
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
+#include "slave.h"
static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
@@ -341,6 +342,36 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
(duplic == DUP_UPDATE))
lock_type=TL_WRITE;
#endif
+ if ((lock_type == TL_WRITE_DELAYED) &&
+ (global_system_variables.binlog_format == BINLOG_FORMAT_STMT) &&
+ log_on && mysql_bin_log.is_open() &&
+ (values_list.elements > 1))
+ {
+ /*
+ Statement-based binary logging does not work in this case, because:
+ a) two concurrent statements may have their rows intermixed in the
+ queue, leading to autoincrement replication problems on slave (because
+ the values generated used for one statement don't depend only on the
+ value generated for the first row of this statement, so are not
+ replicable)
+ b) if first row of the statement has an error the full statement is
+ not binlogged, while next rows of the statement may be inserted.
+ c) if first row succeeds, statement is binlogged immediately with a
+ zero error code (i.e. "no error"), if then second row fails, query
+ will fail on slave too and slave will stop (wrongly believing that the
+ master got no error).
+ So we fallback to non-delayed INSERT.
+ Note that to be fully correct, we should test the "binlog format which
+ the delayed thread is going to use for this row". But in the common case
+ where the global binlog format is not changed and the session binlog
+ format may be changed, that is equal to the global binlog format.
+ We test it without mutex for speed reasons (condition rarely true), and
+ in the common case (global not changed) it is as good as without mutex;
+ if global value is changed, anyway there is uncertainty as the delayed
+ thread may be old and use the before-the-change value.
+ */
+ lock_type= TL_WRITE;
+ }
table_list->lock_type= lock_type;
#ifndef EMBEDDED_LIBRARY
@@ -454,6 +485,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->cuted_fields = 0L;
table->next_number_field=table->found_next_number_field;
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ goto abort;
+#endif
+
error=0;
thd->proc_info="update";
if (duplic != DUP_ERROR || ignore)
@@ -1146,13 +1185,13 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
+ table->file->restore_auto_increment(prev_insert_id);
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
{
- table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
goto err;
@@ -2489,6 +2528,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
+
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ DBUG_RETURN(1);
+#endif
+
thd->cuted_fields=0;
if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);