Commit cf40ae76 authored by unknown's avatar unknown

BUG#24403 (valgrind complained on uninited st_table for InnoDB and RBR):

Fix to correct behaviour of find_and_fetch_row() for tables that have primary keys stored
in storage engines that support the fast method to fetch rows given a primary key. The
method uses position() to retrieve the key for a given record and rnd_pos() to position
the internal "cursor" at the row. Rnd_pos() returns the found record in table->record[0],
so the record has to be moved to table->record[1] for further processing after calling
find_and_fetch_row().


sql/log_event.cc:
  Adding code to one exit branch of find_and_fetch_row() to move output record from
  table->record[0] to table->record[1].
  Adding function to do valgrind memory check.
  Adding valgrind memory checks to check that records are defined when they should be.
  Adding Doxygen comment to find_and_fetch_row() with pre- and post-conditions.
parent a0672f06
...@@ -140,6 +140,21 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len) ...@@ -140,6 +140,21 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len)
} }
#endif /* MYSQL_CLIENT */ #endif /* MYSQL_CLIENT */
#ifdef HAVE_purify
static void
valgrind_check_mem(void *ptr, size_t len)
{
static volatile uchar dummy;
for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p)
{
int const c = *p;
if (c < 128)
dummy= c + 1;
else
dummy = c - 1;
}
}
#endif
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
...@@ -5530,6 +5545,8 @@ unpack_row(RELAY_LOG_INFO *rli, ...@@ -5530,6 +5545,8 @@ unpack_row(RELAY_LOG_INFO *rli,
if (bitmap_is_set(cols, field_ptr - begin_ptr)) if (bitmap_is_set(cols, field_ptr - begin_ptr))
{ {
DBUG_ASSERT(table->record[0] <= f->ptr);
DBUG_ASSERT(f->ptr < table->record[0] + table->s->reclength + (f->pack_length_in_rec() == 0));
f->move_field_offset(offset); f->move_field_offset(offset);
ptr= f->unpack(f->ptr, ptr); ptr= f->unpack(f->ptr, ptr);
f->move_field_offset(-offset); f->move_field_offset(-offset);
...@@ -5564,10 +5581,6 @@ unpack_row(RELAY_LOG_INFO *rli, ...@@ -5564,10 +5581,6 @@ unpack_row(RELAY_LOG_INFO *rli,
{ {
uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG; uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x",
(*field_ptr)->flags, mask,
(*field_ptr)->flags & mask));
if (event_type == WRITE_ROWS_EVENT && if (event_type == WRITE_ROWS_EVENT &&
((*field_ptr)->flags & mask) == mask) ((*field_ptr)->flags & mask) == mask)
{ {
...@@ -5690,7 +5703,6 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) ...@@ -5690,7 +5703,6 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
We also invalidate the query cache for all the tables, since We also invalidate the query cache for all the tables, since
they will now be changed. they will now be changed.
*/ */
TABLE_LIST *ptr; TABLE_LIST *ptr;
for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{ {
...@@ -5747,7 +5759,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) ...@@ -5747,7 +5759,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
if ((error= do_prepare_row(thd, rli, table, row_start, &row_end))) if ((error= do_prepare_row(thd, rli, table, row_start, &row_end)))
break; // We should perform the after-row operation even in break; // We should perform the after-row operation even in
// the case of error // the case of error
DBUG_ASSERT(row_end != NULL); // cannot happen DBUG_ASSERT(row_end != NULL); // cannot happen
DBUG_ASSERT(row_end <= (const char*)m_rows_end); DBUG_ASSERT(row_end <= (const char*)m_rows_end);
...@@ -6423,8 +6435,8 @@ int Write_rows_log_event::do_after_row_operations(TABLE *table, int error) ...@@ -6423,8 +6435,8 @@ int Write_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table, TABLE *table,
char const *row_start, char const *const row_start,
char const **row_end) char const **const row_end)
{ {
DBUG_ASSERT(table != NULL); DBUG_ASSERT(table != NULL);
DBUG_ASSERT(row_start && row_end); DBUG_ASSERT(row_start && row_end);
...@@ -6495,7 +6507,7 @@ copy_extra_record_fields(TABLE *table, ...@@ -6495,7 +6507,7 @@ copy_extra_record_fields(TABLE *table,
my_ptrdiff_t master_fields) my_ptrdiff_t master_fields)
{ {
DBUG_PRINT("info", ("Copying to %p " DBUG_PRINT("info", ("Copying to %p "
"from field %d at offset %u " "from field %ld at offset %u "
"to field %d at offset %u", "to field %d at offset %u",
table->record[0], table->record[0],
master_fields, master_reclength, master_fields, master_reclength,
...@@ -6733,8 +6745,26 @@ static bool record_compare(TABLE *table) ...@@ -6733,8 +6745,26 @@ static bool record_compare(TABLE *table)
/* /*
Find the row given by 'key', if the table has keys, or else use a table scan Find the row given by 'key', if the table has keys, or else use a table scan
to find (and fetch) the row. If the engine allows random access of the to find (and fetch) the row.
records, a combination of position() and rnd_pos() will be used.
If the engine allows random access of the records, a combination of
position() and rnd_pos() will be used.
@param table Pointer to table to search
@param key Pointer to key to use for search, if table has key
@pre <code>table->record[0]</code> shall contain the row to locate
and <code>key</code> shall contain a key to use for searching, if
the engine has a key.
@post If the return value is zero, <code>table->record[1]</code>
will contain the fetched row and the internal "cursor" will refer to
the row. If the return value is non-zero,
<code>table->record[1]</code> is undefined. In either case,
<code>table->record[0]</code> is undefined.
@return Zero if the row was successfully fetched into
<code>table->record[1]</code>, error code otherwise.
*/ */
static int find_and_fetch_row(TABLE *table, byte *key) static int find_and_fetch_row(TABLE *table, byte *key)
...@@ -6756,7 +6786,17 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6756,7 +6786,17 @@ static int find_and_fetch_row(TABLE *table, byte *key)
the "cursor" (i.e., record[0] in this case) at the correct row. the "cursor" (i.e., record[0] in this case) at the correct row.
*/ */
table->file->position(table->record[0]); table->file->position(table->record[0]);
DBUG_RETURN(table->file->rnd_pos(table->record[0], table->file->ref)); int error= table->file->rnd_pos(table->record[0], table->file->ref);
/*
rnd_pos() returns the record in table->record[0], so we have to
move it to table->record[1].
*/
bmove_align(table->record[1], table->record[0], table->s->reclength);
#ifdef HAVE_purify
if (error == 0)
valgrind_check_mem(table->record[1], table->s->reclength);
#endif
DBUG_RETURN(error);
} }
DBUG_ASSERT(table->record[1]); DBUG_ASSERT(table->record[1]);
...@@ -6770,7 +6810,7 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6770,7 +6810,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
int error; int error;
/* We have a key: search the table using the index */ /* We have a key: search the table using the index */
if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE))) if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE)))
return error; DBUG_RETURN(error);
/* /*
We need to set the null bytes to ensure that the filler bit are We need to set the null bytes to ensure that the filler bit are
...@@ -6807,6 +6847,9 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6807,6 +6847,9 @@ static int find_and_fetch_row(TABLE *table, byte *key)
if (table->key_info->flags & HA_NOSAME) if (table->key_info->flags & HA_NOSAME)
{ {
table->file->ha_index_end(); table->file->ha_index_end();
#ifdef HAVE_purify
valgrind_check_mem(table->record[1], table->s->reclength);
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -6883,9 +6926,16 @@ static int find_and_fetch_row(TABLE *table, byte *key) ...@@ -6883,9 +6926,16 @@ static int find_and_fetch_row(TABLE *table, byte *key)
table->file->ha_rnd_end(); table->file->ha_rnd_end();
DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0); DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
#ifdef HAVE_purify
if (error == 0)
valgrind_check_mem(table->record[1], table->s->reclength);
#endif
DBUG_RETURN(error); DBUG_RETURN(error);
} }
#ifdef HAVE_purify
valgrind_check_mem(table->record[1], table->s->reclength);
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
} }
#endif #endif
...@@ -6974,8 +7024,8 @@ int Delete_rows_log_event::do_after_row_operations(TABLE *table, int error) ...@@ -6974,8 +7024,8 @@ int Delete_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table, TABLE *table,
char const *row_start, char const *const row_start,
char const **row_end) char const **const row_end)
{ {
int error; int error;
DBUG_ASSERT(row_start && row_end); DBUG_ASSERT(row_start && row_end);
...@@ -7111,8 +7161,8 @@ int Update_rows_log_event::do_after_row_operations(TABLE *table, int error) ...@@ -7111,8 +7161,8 @@ int Update_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table, TABLE *table,
char const *row_start, char const *const row_start,
char const **row_end) char const **const row_end)
{ {
int error; int error;
DBUG_ASSERT(row_start && row_end); DBUG_ASSERT(row_start && row_end);
...@@ -7127,11 +7177,11 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, ...@@ -7127,11 +7177,11 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
table, m_width, table->record[0], table, m_width, table->record[0],
row_start, &m_cols, row_end, &m_master_reclength, row_start, &m_cols, row_end, &m_master_reclength,
table->read_set, UPDATE_ROWS_EVENT); table->read_set, UPDATE_ROWS_EVENT);
row_start = *row_end; char const *next_start = *row_end;
/* m_after_image is the after image for the update */ /* m_after_image is the after image for the update */
error= unpack_row(rli, error= unpack_row(rli,
table, m_width, m_after_image, table, m_width, m_after_image,
row_start, &m_cols, row_end, &m_master_reclength, next_start, &m_cols, row_end, &m_master_reclength,
table->write_set, UPDATE_ROWS_EVENT); table->write_set, UPDATE_ROWS_EVENT);
DBUG_DUMP("record[0]", (const char *)table->record[0], table->s->reclength); DBUG_DUMP("record[0]", (const char *)table->record[0], table->s->reclength);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment