Below is the list of changes that have just been committed into a local
5.1 repository of mats. When mats does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2008-02-22 15:25:56+01:00, mats@stripped +8 -0
BUG#31502 (5.1.20 -> 5.1.22 Slave crashes if it gets an event w/ data
for non-exist column):
Complimentary patch to fix the fact that type() instead of real_type()
was sent in the table map event. This cause a crash when using ENUM
extra columns since type() is MYSQL_TYPE_STRING and real_type() is
MYSQL_TYPE_ENUM. The packed format for MYSQL_TYPE_STRING is (len,
byte, ...) while the pack format for MYSQL_TYPE_ENUM is just the
integer value as a single byte (which will then be interpreted as the
length of a string by the slave).
sql/field.cc@stripped, 2008-02-22 15:25:43+01:00, mats@stripped +8 -11
Removing debug printouts that are not needed any more.
In Field_string::unpack(), only 'min(field_length,length)' bytes
were read from the log, although 'length' bytes should be read,
since this is what is stored in the log. Changing the code so
that the function advances the point 'length' bytes, but just
copy 'min(field_length,lenght)' bytes from the buffer. This way
there is no risk of buffer overflow when length > field_length.
sql/field.h@stripped, 2008-02-22 15:25:44+01:00, mats@stripped +8 -2
Removing gratuitous virtual for save_field_metadata(): the function
is never overridden. Adding debug printout to save_field_metadata().
sql/log_event.cc@stripped, 2008-02-22 15:25:45+01:00, mats@stripped +1
-1
Storing real_type() instead of type() in the coltype array.
sql/log_event.h@stripped, 2008-02-22 15:25:45+01:00, mats@stripped +2 -1
Removing gratuitous virtual on save_field_metadata(): the
function is never overridden. Adding end of all rows to
unpack_row() to allow for checking if reading out of bounds.
sql/log_event_old.h@stripped, 2008-02-22 15:25:45+01:00, mats@stripped +1
-0
Adding end of all rows to unpack_row() to allow for checking
if reading out of bounds.
sql/rpl_record.cc@stripped, 2008-02-22 15:25:46+01:00, mats@stripped +20
-13
Adding end of all rows to unpack_row() to allow for checking
if reading out of bounds. Returning error if reading out of
bounds. Some changes to debug printout to get good information
for debugging.
sql/rpl_record.h@stripped, 2008-02-22 15:25:46+01:00, mats@stripped +1 -0
Adding parameter for end of all rows to allow check for
reading out of bounds data.
sql/rpl_utility.cc@stripped, 2008-02-22 15:25:46+01:00, mats@stripped +22
-6
Not printing an error for field types that require metadata
when we have a length value, i.e., when there were metadata
available for the field.
diff -Nrup a/sql/field.cc b/sql/field.cc
--- a/sql/field.cc 2007-11-21 21:09:21 +01:00
+++ b/sql/field.cc 2008-02-22 15:25:43 +01:00
@@ -4036,39 +4036,35 @@ uchar *
Field_real::pack(uchar *to, const uchar *from,
uint max_length, bool low_byte_first)
{
- DBUG_ENTER("Field_real::pack");
DBUG_ASSERT(max_length >= pack_length());
- DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
#ifdef WORDS_BIGENDIAN
if (low_byte_first != table->s->db_low_byte_first)
{
const uchar *dptr= from + pack_length();
while (dptr-- > from)
*to++ = *dptr;
- DBUG_RETURN(to);
+ return to;
}
else
#endif
- DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first));
+ return Field::pack(to, from, max_length, low_byte_first);
}
const uchar *
Field_real::unpack(uchar *to, const uchar *from,
uint param_data, bool low_byte_first)
{
- DBUG_ENTER("Field_real::unpack");
- DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
#ifdef WORDS_BIGENDIAN
if (low_byte_first != table->s->db_low_byte_first)
{
const uchar *dptr= from + pack_length();
while (dptr-- > from)
*to++ = *dptr;
- DBUG_RETURN(from + pack_length());
+ return from + pack_length();
}
else
#endif
- DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first));
+ return Field::unpack(to, from, param_data, low_byte_first);
}
/****************************************************************************
@@ -6675,7 +6671,7 @@ Field_string::unpack(uchar *to,
bool low_byte_first __attribute__((unused)))
{
uint from_length=
- param_data ? min(param_data & 0x00ff, field_length) : field_length;
+ param_data ? (param_data & 0x00ff) : field_length;
uint length;
if (from_length > 255)
@@ -6686,9 +6682,10 @@ Field_string::unpack(uchar *to,
else
length= (uint) *from++;
- memcpy(to, from, length);
+ memcpy(to, from, min(length, field_length));
// Pad the string with the pad character of the fields charset
- bfill(to + length, field_length - length, field_charset->pad_char);
+ if (field_length > length)
+ bfill(to + length, field_length - length, field_charset->pad_char);
return from+length;
}
diff -Nrup a/sql/field.h b/sql/field.h
--- a/sql/field.h 2007-10-30 08:19:22 +01:00
+++ b/sql/field.h 2008-02-22 15:25:44 +01:00
@@ -167,8 +167,14 @@ public:
field_length + 1, field_length, and pack_length_no_ptr() respectfully.
*/
virtual uint row_pack_length() { return 0; }
- virtual int save_field_metadata(uchar *first_byte)
- { return do_save_field_metadata(first_byte); }
+ int save_field_metadata(uchar *first_byte)
+ {
+ int result= do_save_field_metadata(first_byte);
+ DBUG_PRINT("info", ("field: %s; type: %3d; count: %2d, data: %02x %02x",
+ field_name, real_type(), result,
+ first_byte[0], first_byte[1]));
+ return result;
+ }
/*
data_length() return the "real size" of the data in memory.
diff -Nrup a/sql/log_event.cc b/sql/log_event.cc
--- a/sql/log_event.cc 2007-12-13 21:27:23 +01:00
+++ b/sql/log_event.cc 2008-02-22 15:25:45 +01:00
@@ -6852,7 +6852,7 @@ Table_map_log_event::Table_map_log_event
{
m_coltype= reinterpret_cast<uchar*>(m_memory);
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- m_coltype[i]= m_table->field[i]->type();
+ m_coltype[i]= m_table->field[i]->real_type();
}
/*
diff -Nrup a/sql/log_event.h b/sql/log_event.h
--- a/sql/log_event.h 2007-12-13 21:27:23 +01:00
+++ b/sql/log_event.h 2008-02-22 15:25:45 +01:00
@@ -2874,7 +2874,7 @@ public:
virtual int get_data_size() { return m_data_size; }
#ifndef MYSQL_CLIENT
- virtual int save_field_metadata();
+ int save_field_metadata();
virtual bool write_data_header(IO_CACHE *file);
virtual bool write_data_body(IO_CACHE *file);
virtual const char *get_db() { return m_dbnam; }
@@ -3097,6 +3097,7 @@ protected:
DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
+ m_rows_end,
&m_curr_row_end, &m_master_reclength);
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result;
diff -Nrup a/sql/log_event_old.h b/sql/log_event_old.h
--- a/sql/log_event_old.h 2007-11-20 19:49:34 +01:00
+++ b/sql/log_event_old.h 2008-02-22 15:25:45 +01:00
@@ -212,6 +212,7 @@ protected:
DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
+ m_rows_end,
&m_curr_row_end, &m_master_reclength);
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result;
diff -Nrup a/sql/rpl_record.cc b/sql/rpl_record.cc
--- a/sql/rpl_record.cc 2007-12-13 21:27:24 +01:00
+++ b/sql/rpl_record.cc 2008-02-22 15:25:46 +01:00
@@ -77,8 +77,10 @@ pack_row(TABLE *table, MY_BITMAP const*
unsigned int null_mask= 1U;
for ( ; (field= *p_field) ; p_field++)
{
- DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
- null_mask, null_ptr, row_data, null_byte_count));
+ DBUG_PRINT("debug", ("field: %s; type: %d",
+ field->field_name, field->real_type()));
+ DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; null_byte_count=%d",
+ null_mask, null_ptr, null_byte_count));
if (bitmap_is_set(cols, p_field - table->field))
{
my_ptrdiff_t offset;
@@ -104,11 +106,10 @@ pack_row(TABLE *table, MY_BITMAP const*
#endif
pack_ptr= field->pack(pack_ptr, field->ptr + offset,
field->max_data_length(), TRUE);
- DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;"
- " pack_ptr':0x%lx; bytes: %d",
- field->field_name, (ulong) old_pack_ptr,
- (ulong) pack_ptr,
+ DBUG_PRINT("debug", ("pack_ptr: 0x%lx; pack_ptr':0x%lx; bytes: %d",
+ (ulong) old_pack_ptr, (ulong) pack_ptr,
(int) (pack_ptr - old_pack_ptr)));
+ DBUG_DUMP("row_data", old_pack_ptr, pack_ptr - old_pack_ptr);
}
null_mask <<= 1;
@@ -186,6 +187,7 @@ int
unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
+ uchar const *const data_end,
uchar const **const row_end, ulong *const master_reclength)
{
DBUG_ENTER("unpack_row");
@@ -247,11 +249,12 @@ unpack_row(Relay_log_info const *rli,
uchar const *const old_pack_ptr= pack_ptr;
#endif
pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE);
- DBUG_PRINT("debug", ("field: %s; type: %d; metadata: 0x%x;"
- " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
- f->field_name, f->type(), metadata,
+ DBUG_PRINT("debug", ("field: %s; type: %d; metadata: 0x%x",
+ f->field_name, f->type(), metadata));
+ DBUG_PRINT("debug", ("pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
(ulong) old_pack_ptr, (ulong) pack_ptr,
(int) (pack_ptr - old_pack_ptr)));
+ DBUG_DUMP("row_data", old_pack_ptr, pack_ptr - old_pack_ptr);
}
null_mask <<= 1;
@@ -262,8 +265,8 @@ unpack_row(Relay_log_info const *rli,
/*
throw away master's extra fields
*/
- DBUG_PRINT("info", ("i: %u; tabledef->size: %lu; cols->n_bits: %u",
- i, tabledef->size(), cols->n_bits));
+ DBUG_PRINT("info", ("tabledef->size: %lu; cols->n_bits: %u",
+ tabledef->size(), cols->n_bits));
uint max_cols= min(tabledef->size(), cols->n_bits);
for (; i < max_cols; i++)
{
@@ -282,9 +285,13 @@ unpack_row(Relay_log_info const *rli,
if ((error= tabledef->calc_field_size(i, (uchar *) pack_ptr, &length,
rli)))
DBUG_RETURN(error);
DBUG_PRINT("info",
- ("type: %d; pack_ptr: 0x%lu; pack_ptr': 0x%lu",
- tabledef->type(i),
+ ("type: %d; metadata: 0x%04x; bytes: %d",
+ tabledef->type(i), tabledef->field_metadata(i), length));
+ DBUG_PRINT("info",
+ ("pack_ptr: 0x%lu; pack_ptr': 0x%lu",
(ulong) pack_ptr, (ulong) pack_ptr + length));
+ DBUG_DUMP("row_data", pack_ptr, min(length, 128));
+ ASSERT_OR_RETURN_ERROR(pack_ptr + length <= data_end, HA_ERR_CORRUPT_EVENT);
pack_ptr += length;
}
null_mask <<= 1;
diff -Nrup a/sql/rpl_record.h b/sql/rpl_record.h
--- a/sql/rpl_record.h 2007-09-10 13:15:59 +02:00
+++ b/sql/rpl_record.h 2008-02-22 15:25:46 +01:00
@@ -27,6 +27,7 @@ size_t pack_row(TABLE* table, MY_BITMAP
int unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
+ uchar const *const data_end,
uchar const **const row_end, ulong *const master_reclength);
// Fill table's record[0] with default values.
diff -Nrup a/sql/rpl_utility.cc b/sql/rpl_utility.cc
--- a/sql/rpl_utility.cc 2007-12-13 21:27:24 +01:00
+++ b/sql/rpl_utility.cc 2008-02-22 15:25:46 +01:00
@@ -77,9 +77,14 @@ check_and_set_length(enum_field_types fi
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_BIT:
case MYSQL_TYPE_DECIMAL: // ???
- log->report(ERROR_LEVEL, ER_SLAVE_MISSING_METADATA,
- ER(ER_SLAVE_MISSING_METDATA), field_type);
- error= HA_ERR_SLAVE_MISSING_METADATA;
+ if (length)
+ *out_length = length;
+ else
+ {
+ log->report(ERROR_LEVEL, ER_SLAVE_MISSING_METADATA,
+ ER(ER_SLAVE_MISSING_METADATA), field_type);
+ error= HA_ERR_SLAVE_MISSING_METADATA;
+ }
break;
}
return error;
@@ -192,7 +197,7 @@ table_def::calc_field_size(uint col, uch
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
{
-#if 1
+#if 0
/*
BUG#29549:
This is currently broken for NDB, which is using big-endian
@@ -232,7 +237,7 @@ table_def::calc_field_size(uint col, uch
break;
}
default:
- length= -1;
+ length= 0;
}
int const error= check_and_set_length(type(col), length, log, len_arg);
@@ -258,7 +263,18 @@ table_def::compatible_with(Relay_log_inf
for (uint col= 0 ; col < cols_to_check ; ++col)
{
- if (table->field[col]->type() != type(col))
+ /*
+ Here we check if the type we received is different from the real
+ type of the column. If it is, there is a problem and an error is
+ reported.
+
+ To be able to replication from old servers not having metadata,
+ we check the type (instead of the real type) since this is what
+ was stored instead of the real type.
+ */
+ if (table->field[col]->real_type() != type(col) ||
+ (m_field_metadata[col] == 0 &&
+ table->field[col]->real_type() != type(col)))
{
DBUG_ASSERT(col < size() && col < tsh->fields);
DBUG_ASSERT(tsh->db.str && tsh->table_name.str);