Added detection of memory overwrite with multi_malloc

This patch also fixes some bugs detected by valgrind after this
patch:

- Not enough copy_func elements was allocated by Create_tmp_table() which
  causes an memory overwrite in Create_tmp_table::add_fields()
  I added an ASSERT() to be able to detect this also without valgrind.
  The bug was that TMP_TABLE_PARAM::copy_fields was not correctly set
  when calling create_tmp_table().
- Aria::empty_bits is not allocated if there is no varchar/char/blob
  fields in the table.  Fixed code to take this into account.
  This cannot cause any issues as this is just a memory access
  into other Aria memory and the content of the memory would not be used.
- Aria::last_key_buff was not allocated big enough. This may have caused
  issues with rtrees and ma_extra(HA_EXTRA_REMEMBER_POS) as they
  would use the same memory area.
- Aria and MyISAM didn't take extended key parts into account, which
  caused problems when copying rec_per_key from engine to sql level.
- Mark asan builds with 'asan' in version strihng to detect these in
  not_valgrind_build.inc.
  This is needed to not have main.sp-no-valgrind fail with asan.
This commit is contained in:
Monty 2023-02-26 18:33:10 +02:00
parent 0de3be8cfd
commit 57c526ffb8
18 changed files with 136 additions and 58 deletions

View file

@ -17,7 +17,7 @@
path=`dirname $0` path=`dirname $0`
. "$path/SETUP.sh" . "$path/SETUP.sh"
extra_flags="$pentium64_cflags $debug_cflags -lasan -O -g -fsanitize=address -USAFEMALLOC -UFORCE_INIT_OF_VARS -Wno-uninitialized -Wno-maybe-uninitialized" extra_flags="$pentium64_cflags $debug_cflags -lasan -O -g -fsanitize=address -USAFEMALLOC -UFORCE_INIT_OF_VARS -Wno-uninitialized -Wno-maybe-uninitialized -DMYSQL_SERVER_SUFFIX=-asan-max"
extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs $disable_asan_plugins" extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs $disable_asan_plugins"
export LDFLAGS="-ldl" export LDFLAGS="-ldl"

View file

@ -1,4 +1,4 @@
if (`select version() like '%valgrind%'`) if (`select version() like '%valgrind%' || version() like '%asan%'`)
{ {
skip Does not run with binaries built with valgrind; skip Does not run with binaries built with valgrind or asan;
} }

View file

@ -1,5 +1,7 @@
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/have_debug.inc --source include/have_debug.inc
# Valgrind builds may block on this one
--source include/not_valgrind.inc
SET @start_global_value = @@global.innodb_log_checkpoint_now; SET @start_global_value = @@global.innodb_log_checkpoint_now;
SELECT @start_global_value; SELECT @start_global_value;

View file

@ -17,6 +17,11 @@
#include "mysys_priv.h" #include "mysys_priv.h"
#include <stdarg.h> #include <stdarg.h>
#ifndef DBUG_OFF
/* Put a protected barrier after every element when using my_multi_malloc() */
#define ALLOC_BARRIER
#endif
/* /*
Malloc many pointers at the same time Malloc many pointers at the same time
Only ptr1 can be free'd, and doing this will free all Only ptr1 can be free'd, and doing this will free all
@ -45,6 +50,9 @@ void* my_multi_malloc(PSI_memory_key key, myf myFlags, ...)
{ {
length=va_arg(args,uint); length=va_arg(args,uint);
tot_length+=ALIGN_SIZE(length); tot_length+=ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
tot_length+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
@ -58,6 +66,10 @@ void* my_multi_malloc(PSI_memory_key key, myf myFlags, ...)
*ptr=res; *ptr=res;
length=va_arg(args,uint); length=va_arg(args,uint);
res+=ALIGN_SIZE(length); res+=ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
TRASH_FREE(res, ALIGN_SIZE(1));
res+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
DBUG_RETURN((void*) start); DBUG_RETURN((void*) start);
@ -89,6 +101,9 @@ void *my_multi_malloc_large(PSI_memory_key key, myf myFlags, ...)
{ {
length=va_arg(args,ulonglong); length=va_arg(args,ulonglong);
tot_length+=ALIGN_SIZE(length); tot_length+=ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
tot_length+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
@ -102,6 +117,10 @@ void *my_multi_malloc_large(PSI_memory_key key, myf myFlags, ...)
*ptr=res; *ptr=res;
length=va_arg(args,ulonglong); length=va_arg(args,ulonglong);
res+=ALIGN_SIZE(length); res+=ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
TRASH_FREE(res, ALIGN_SIZE(1));
res+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
DBUG_RETURN((void*) start); DBUG_RETURN((void*) start);

View file

@ -23,6 +23,11 @@
#undef EXTRA_DEBUG #undef EXTRA_DEBUG
#define EXTRA_DEBUG #define EXTRA_DEBUG
#ifndef DBUG_OFF
/* Put a protected barrier after every element when using multi_alloc_root() */
#define ALLOC_BARRIER
#endif
/* data packed in MEM_ROOT -> min_malloc */ /* data packed in MEM_ROOT -> min_malloc */
#define MALLOC_FLAG(A) ((A & 1) ? MY_THREAD_SPECIFIC : 0) #define MALLOC_FLAG(A) ((A & 1) ? MY_THREAD_SPECIFIC : 0)
@ -311,6 +316,9 @@ void *multi_alloc_root(MEM_ROOT *root, ...)
{ {
length= va_arg(args, uint); length= va_arg(args, uint);
tot_length+= ALIGN_SIZE(length); tot_length+= ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
tot_length+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
@ -324,6 +332,10 @@ void *multi_alloc_root(MEM_ROOT *root, ...)
*ptr= res; *ptr= res;
length= va_arg(args, uint); length= va_arg(args, uint);
res+= ALIGN_SIZE(length); res+= ALIGN_SIZE(length);
#ifdef ALLOC_BARRIER
TRASH_FREE(res, ALIGN_SIZE(1));
res+= ALIGN_SIZE(1);
#endif
} }
va_end(args); va_end(args);
DBUG_RETURN((void*) start); DBUG_RETURN((void*) start);

View file

@ -4174,6 +4174,7 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
} }
sjm->sjm_table_param.field_count= subq_select->item_list.elements; sjm->sjm_table_param.field_count= subq_select->item_list.elements;
sjm->sjm_table_param.func_count= sjm->sjm_table_param.field_count;
sjm->sjm_table_param.force_not_null_cols= TRUE; sjm->sjm_table_param.force_not_null_cols= TRUE;
if (!(sjm->table= create_tmp_table(thd, &sjm->sjm_table_param, if (!(sjm->table= create_tmp_table(thd, &sjm->sjm_table_param,
@ -5789,14 +5790,14 @@ TABLE *create_dummy_tmp_table(THD *thd)
DBUG_ENTER("create_dummy_tmp_table"); DBUG_ENTER("create_dummy_tmp_table");
TABLE *table; TABLE *table;
TMP_TABLE_PARAM sjm_table_param; TMP_TABLE_PARAM sjm_table_param;
sjm_table_param.init();
sjm_table_param.field_count= 1;
List<Item> sjm_table_cols; List<Item> sjm_table_cols;
const LEX_CSTRING dummy_name= { STRING_WITH_LEN("dummy") }; const LEX_CSTRING dummy_name= { STRING_WITH_LEN("dummy") };
Item *column_item= new (thd->mem_root) Item_int(thd, 1); Item *column_item= new (thd->mem_root) Item_int(thd, 1);
if (!column_item) if (!column_item)
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
sjm_table_param.init();
sjm_table_param.field_count= sjm_table_param.func_count= 1;
sjm_table_cols.push_back(column_item, thd->mem_root); sjm_table_cols.push_back(column_item, thd->mem_root);
if (!(table= create_tmp_table(thd, &sjm_table_param, if (!(table= create_tmp_table(thd, &sjm_table_param,
sjm_table_cols, (ORDER*) 0, sjm_table_cols, (ORDER*) 0,

View file

@ -51,18 +51,19 @@ select_handler::~select_handler()
TABLE *select_handler::create_tmp_table(THD *thd, SELECT_LEX *select) TABLE *select_handler::create_tmp_table(THD *thd, SELECT_LEX *select)
{ {
DBUG_ENTER("select_handler::create_tmp_table");
List<Item> types; List<Item> types;
TMP_TABLE_PARAM tmp_table_param; TMP_TABLE_PARAM tmp_table_param;
TABLE *table;
DBUG_ENTER("select_handler::create_tmp_table");
if (select->master_unit()->join_union_item_types(thd, types, 1)) if (select->master_unit()->join_union_item_types(thd, types, 1))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
tmp_table_param.init(); tmp_table_param.init();
tmp_table_param.field_count= types.elements; tmp_table_param.field_count= tmp_table_param.func_count= types.elements;
table= ::create_tmp_table(thd, &tmp_table_param, types,
TABLE *table= ::create_tmp_table(thd, &tmp_table_param, types, (ORDER *) 0, false, 0,
(ORDER *) 0, false, 0, TMP_TABLE_ALL_COLUMNS, 1,
TMP_TABLE_ALL_COLUMNS, 1, &empty_clex_str, true, false);
&empty_clex_str, true, false);
DBUG_RETURN(table); DBUG_RETURN(table);
} }

View file

@ -4310,6 +4310,7 @@ create_result_table(THD *thd_arg, List<Item> *column_types,
{ {
DBUG_ASSERT(table == 0); DBUG_ASSERT(table == 0);
tmp_table_param.field_count= column_types->elements; tmp_table_param.field_count= column_types->elements;
tmp_table_param.func_count= tmp_table_param.field_count;
tmp_table_param.bit_fields_as_long= bit_fields_as_long; tmp_table_param.bit_fields_as_long= bit_fields_as_long;
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,

View file

@ -5986,6 +5986,7 @@ public:
@see opt_sum_query, count_field_types @see opt_sum_query, count_field_types
*/ */
uint sum_func_count; uint sum_func_count;
uint copy_func_count; // Allocated copy fields
uint hidden_field_count; uint hidden_field_count;
uint group_parts,group_length,group_null_parts; uint group_parts,group_length,group_null_parts;

View file

@ -114,7 +114,7 @@ void Expression_cache_tmptable::init()
cache_table_param.init(); cache_table_param.init();
/* dependent items and result */ /* dependent items and result */
cache_table_param.field_count= items.elements; cache_table_param.field_count= cache_table_param.func_count= items.elements;
/* postpone table creation to index description */ /* postpone table creation to index description */
cache_table_param.skip_create_table= 1; cache_table_param.skip_create_table= 1;

View file

@ -3325,7 +3325,9 @@ bool JOIN::make_aggr_tables_info()
if (gbh) if (gbh)
{ {
if (!(pushdown_query= new (thd->mem_root) Pushdown_query(select_lex, gbh))) TABLE *table;
if (!(pushdown_query= new (thd->mem_root) Pushdown_query(select_lex,
gbh)))
DBUG_RETURN(1); DBUG_RETURN(1);
/* /*
We must store rows in the tmp table if we need to do an ORDER BY We must store rows in the tmp table if we need to do an ORDER BY
@ -3345,13 +3347,13 @@ bool JOIN::make_aggr_tables_info()
if (!(curr_tab->tmp_table_param= new TMP_TABLE_PARAM(tmp_table_param))) if (!(curr_tab->tmp_table_param= new TMP_TABLE_PARAM(tmp_table_param)))
DBUG_RETURN(1); DBUG_RETURN(1);
TABLE* table= create_tmp_table(thd, curr_tab->tmp_table_param, curr_tab->tmp_table_param->func_count= all_fields.elements;
all_fields, if (!(table= create_tmp_table(thd, curr_tab->tmp_table_param,
NULL, query.distinct, all_fields,
TRUE, select_options, HA_POS_ERROR, NULL, query.distinct,
&empty_clex_str, !need_tmp, TRUE, select_options, HA_POS_ERROR,
query.order_by || query.group_by); &empty_clex_str, !need_tmp,
if (!table) query.order_by || query.group_by)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(curr_tab->aggr= new (thd->mem_root) AGGR_OP(curr_tab))) if (!(curr_tab->aggr= new (thd->mem_root) AGGR_OP(curr_tab)))
@ -18805,6 +18807,7 @@ TABLE *Create_tmp_table::start(THD *thd,
*/ */
if (param->precomputed_group_by) if (param->precomputed_group_by)
copy_func_count+= param->sum_func_count; copy_func_count+= param->sum_func_count;
param->copy_func_count= copy_func_count;
init_sql_alloc(key_memory_TABLE, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0, init_sql_alloc(key_memory_TABLE, &own_root, TABLE_ALLOC_BLOCK_SIZE, 0,
MYF(MY_THREAD_SPECIFIC)); MYF(MY_THREAD_SPECIFIC));
@ -19010,8 +19013,9 @@ bool Create_tmp_table::add_fields(THD *thd,
We here distinguish between UNION and multi-table-updates by the fact We here distinguish between UNION and multi-table-updates by the fact
that in the later case group is set to the row pointer. that in the later case group is set to the row pointer.
The test for item->marker == 4 is ensure we don't create a group-by The test for item->marker == MARKER_NULL_KEY is ensure we
key over a bit field as heap tables can't handle that. don't create a group-by key over a bit field as heap tables
can't handle that.
*/ */
DBUG_ASSERT(!param->schema_table); DBUG_ASSERT(!param->schema_table);
Field *new_field= Field *new_field=
@ -19076,6 +19080,7 @@ bool Create_tmp_table::add_fields(THD *thd,
new_field->flags|= FIELD_PART_OF_TMP_UNIQUE; new_field->flags|= FIELD_PART_OF_TMP_UNIQUE;
} }
} }
DBUG_ASSERT(fieldnr == m_field_count[other] + m_field_count[distinct]); DBUG_ASSERT(fieldnr == m_field_count[other] + m_field_count[distinct]);
DBUG_ASSERT(m_blob_count == m_blobs_count[other] + m_blobs_count[distinct]); DBUG_ASSERT(m_blob_count == m_blobs_count[other] + m_blobs_count[distinct]);
share->fields= fieldnr; share->fields= fieldnr;
@ -19083,7 +19088,9 @@ bool Create_tmp_table::add_fields(THD *thd,
table->field[fieldnr]= 0; // End marker table->field[fieldnr]= 0; // End marker
share->blob_field[m_blob_count]= 0; // End marker share->blob_field[m_blob_count]= 0; // End marker
copy_func[0]= 0; // End marker copy_func[0]= 0; // End marker
DBUG_ASSERT((copy_func - param->items_to_copy) <= param->copy_func_count);
param->func_count= (uint) (copy_func - param->items_to_copy); param->func_count= (uint) (copy_func - param->items_to_copy);
share->column_bitmap_size= bitmap_buffer_size(share->fields); share->column_bitmap_size= bitmap_buffer_size(share->fields);
thd->mem_root= mem_root_save; thd->mem_root= mem_root_save;
@ -26461,6 +26468,11 @@ bool JOIN::rollup_init()
Item **ref_array; Item **ref_array;
tmp_table_param.quick_group= 0; // Can't create groups in tmp table tmp_table_param.quick_group= 0; // Can't create groups in tmp table
/*
Each group can potentially be replaced with Item_func_rollup_const() which
needs a copy_func placeholder.
*/
tmp_table_param.func_count+= send_group_parts;
rollup.state= ROLLUP::STATE_INITED; rollup.state= ROLLUP::STATE_INITED;
/* /*
@ -26485,7 +26497,6 @@ bool JOIN::rollup_init()
ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
/* /*
Prepare space for field list for the different levels Prepare space for field list for the different levels
These will be filled up in rollup_make_fields() These will be filled up in rollup_make_fields()
@ -26650,7 +26661,6 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
/* Point to first hidden field */ /* Point to first hidden field */
uint ref_array_ix= fields_arg.elements-1; uint ref_array_ix= fields_arg.elements-1;
/* Remember where the sum functions ends for the previous level */ /* Remember where the sum functions ends for the previous level */
sum_funcs_end[pos+1]= *func; sum_funcs_end[pos+1]= *func;

View file

@ -8216,28 +8216,34 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
TABLE *table; TABLE *table;
ST_SCHEMA_TABLE *schema_table= table_list->schema_table; ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
ST_FIELD_INFO *fields= schema_table->fields_info; ST_FIELD_INFO *fields= schema_table->fields_info;
bool need_all_fieds= table_list->schema_table_reformed || // SHOW command bool need_all_fields= table_list->schema_table_reformed || // SHOW command
thd->lex->only_view_structure(); // need table structure thd->lex->only_view_structure(); // need table structure
bool keep_row_order;
TMP_TABLE_PARAM *tmp_table_param;
SELECT_LEX *select_lex;
my_bitmap_map *bitmaps;
DBUG_ENTER("create_schema_table"); DBUG_ENTER("create_schema_table");
for (; !fields->end_marker(); fields++) for (; !fields->end_marker(); fields++)
field_count++; field_count++;
TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM; tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM;
tmp_table_param->init(); tmp_table_param->init();
tmp_table_param->table_charset= system_charset_info; tmp_table_param->table_charset= system_charset_info;
tmp_table_param->field_count= field_count; tmp_table_param->field_count= field_count;
tmp_table_param->schema_table= 1; tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= table_list->select_lex; select_lex= table_list->select_lex;
bool keep_row_order= is_show_command(thd); keep_row_order= is_show_command(thd);
if (!(table= create_tmp_table_for_schema(thd, tmp_table_param, *schema_table, if (!(table=
(select_lex->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS), create_tmp_table_for_schema(thd, tmp_table_param, *schema_table,
table_list->alias, !need_all_fieds, keep_row_order))) (select_lex->options |
thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS),
table_list->alias, !need_all_fields,
keep_row_order)))
DBUG_RETURN(0); DBUG_RETURN(0);
my_bitmap_map* bitmaps= bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); my_bitmap_init(&table->def_read_set, bitmaps, field_count, FALSE);
my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
FALSE);
table->read_set= &table->def_read_set; table->read_set= &table->def_read_set;
bitmap_clear_all(table->read_set); bitmap_clear_all(table->read_set);
table_list->schema_table_param= tmp_table_param; table_list->schema_table_param= tmp_table_param;

View file

@ -344,6 +344,7 @@ select_unit::create_result_table(THD *thd_arg, List<Item> *column_types,
DBUG_ASSERT(table == 0); DBUG_ASSERT(table == 0);
tmp_table_param.init(); tmp_table_param.init();
tmp_table_param.field_count= column_types->elements; tmp_table_param.field_count= column_types->elements;
tmp_table_param.func_count= tmp_table_param.field_count;
tmp_table_param.bit_fields_as_long= bit_fields_as_long; tmp_table_param.bit_fields_as_long= bit_fields_as_long;
tmp_table_param.hidden_field_count= hidden; tmp_table_param.hidden_field_count= hidden;
@ -384,7 +385,8 @@ select_union_recursive::create_result_table(THD *thd_arg,
return true; return true;
incr_table_param.init(); incr_table_param.init();
incr_table_param.field_count= column_types->elements; incr_table_param.field_count= incr_table_param.func_count=
column_types->elements;
incr_table_param.bit_fields_as_long= bit_fields_as_long; incr_table_param.bit_fields_as_long= bit_fields_as_long;
if (! (incr_table= create_tmp_table(thd_arg, &incr_table_param, *column_types, if (! (incr_table= create_tmp_table(thd_arg, &incr_table_param, *column_types,
(ORDER*) 0, false, 1, (ORDER*) 0, false, 1,

View file

@ -912,9 +912,8 @@ bool THD::has_temporary_tables()
uint THD::create_tmp_table_def_key(char *key, const char *db, uint THD::create_tmp_table_def_key(char *key, const char *db,
const char *table_name) const char *table_name)
{ {
DBUG_ENTER("THD::create_tmp_table_def_key");
uint key_length; uint key_length;
DBUG_ENTER("THD::create_tmp_table_def_key");
key_length= tdc_create_key(key, db, table_name); key_length= tdc_create_key(key, db, table_name);
int4store(key + key_length, variables.server_id); int4store(key + key_length, variables.server_id);
@ -1163,11 +1162,10 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share,
*/ */
bool THD::find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table) bool THD::find_and_use_tmp_table(const TABLE_LIST *tl, TABLE **out_table)
{ {
DBUG_ENTER("THD::find_and_use_tmp_table");
char key[MAX_DBKEY_LENGTH]; char key[MAX_DBKEY_LENGTH];
uint key_length; uint key_length;
bool result; bool result;
DBUG_ENTER("THD::find_and_use_tmp_table");
key_length= create_tmp_table_def_key(key, tl->get_db_name(), key_length= create_tmp_table_def_key(key, tl->get_db_name(),
tl->get_table_name()); tl->get_table_name());

View file

@ -2630,12 +2630,22 @@ int ha_maria::info(uint flag)
share->db_record_offset= maria_info.record_offset; share->db_record_offset= maria_info.record_offset;
if (share->key_parts) if (share->key_parts)
{ {
ulong *to= table->key_info[0].rec_per_key, *end;
double *from= maria_info.rec_per_key; double *from= maria_info.rec_per_key;
for (end= to+ share->key_parts ; to < end ; to++, from++) KEY *key, *key_end;
*to= (ulong) (*from + 0.5); for (key= table->key_info, key_end= key + share->keys;
key < key_end ; key++)
{
ulong *to= key->rec_per_key;
/* Some temporary tables does not allocate rec_per_key */
if (to)
{
for (ulong *end= to+ key->user_defined_key_parts ;
to < end ;
to++, from++)
*to= (ulong) (*from + 0.5);
}
}
} }
/* /*
Set data_file_name and index_file_name to point at the symlink value Set data_file_name and index_file_name to point at the symlink value
if table is symlinked (Ie; Real name is not same as generated name) if table is symlinked (Ie; Real name is not same as generated name)

View file

@ -2774,7 +2774,8 @@ static my_bool write_block_record(MARIA_HA *info,
const uchar *field_pos; const uchar *field_pos;
ulong length; ulong length;
if ((record[column->null_pos] & column->null_bit) || if ((record[column->null_pos] & column->null_bit) ||
(row->empty_bits[column->empty_pos] & column->empty_bit)) (column->empty_bit &&
(row->empty_bits[column->empty_pos] & column->empty_bit)))
continue; continue;
field_pos= record + column->offset; field_pos= record + column->offset;
@ -4872,7 +4873,8 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
uchar *field_pos= record + column->offset; uchar *field_pos= record + column->offset;
/* First check if field is present in record */ /* First check if field is present in record */
if ((record[column->null_pos] & column->null_bit) || if ((record[column->null_pos] & column->null_bit) ||
(cur_row->empty_bits[column->empty_pos] & column->empty_bit)) (column->empty_bit &&
(cur_row->empty_bits[column->empty_pos] & column->empty_bit)))
{ {
bfill(record + column->offset, column->fill_length, bfill(record + column->offset, column->fill_length,
type == FIELD_SKIP_ENDSPACE ? ' ' : 0); type == FIELD_SKIP_ENDSPACE ? ' ' : 0);
@ -4951,8 +4953,9 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
{ {
uint size_length; uint size_length;
if ((record[blob_field->null_pos] & blob_field->null_bit) || if ((record[blob_field->null_pos] & blob_field->null_bit) ||
(cur_row->empty_bits[blob_field->empty_pos] & (blob_field->empty_bit &
blob_field->empty_bit)) (cur_row->empty_bits[blob_field->empty_pos] &
blob_field->empty_bit)))
continue; continue;
size_length= blob_field->length - portable_sizeof_char_ptr; size_length= blob_field->length - portable_sizeof_char_ptr;
blob_lengths+= _ma_calc_blob_length(size_length, length_data); blob_lengths+= _ma_calc_blob_length(size_length, length_data);
@ -5806,7 +5809,8 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
const uchar *column_pos; const uchar *column_pos;
size_t column_length; size_t column_length;
if ((record[column->null_pos] & column->null_bit) || if ((record[column->null_pos] & column->null_bit) ||
cur_row->empty_bits[column->empty_pos] & column->empty_bit) (column->empty_bit &&
cur_row->empty_bits[column->empty_pos] & column->empty_bit))
continue; continue;
column_pos= record+ column->offset; column_pos= record+ column->offset;
@ -5987,7 +5991,8 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
*/ */
continue; continue;
} }
if (old_row->empty_bits[column->empty_pos] & column->empty_bit) if (column->empty_bit &&
(old_row->empty_bits[column->empty_pos] & column->empty_bit))
{ {
if (new_row->empty_bits[column->empty_pos] & column->empty_bit) if (new_row->empty_bits[column->empty_pos] & column->empty_bit)
continue; /* Both are empty; skip */ continue; /* Both are empty; skip */
@ -6003,8 +6008,9 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
log the original value log the original value
*/ */
new_column_is_empty= ((newrec[column->null_pos] & column->null_bit) || new_column_is_empty= ((newrec[column->null_pos] & column->null_bit) ||
(new_row->empty_bits[column->empty_pos] & (column->empty_bit &&
column->empty_bit)); (new_row->empty_bits[column->empty_pos] &
column->empty_bit)));
old_column_pos= oldrec + column->offset; old_column_pos= oldrec + column->offset;
new_column_pos= newrec + column->offset; new_column_pos= newrec + column->offset;
@ -7177,7 +7183,8 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
column++, null_field_lengths++) column++, null_field_lengths++)
{ {
if ((record[column->null_pos] & column->null_bit) || if ((record[column->null_pos] & column->null_bit) ||
row.empty_bits[column->empty_pos] & column->empty_bit) (column->empty_bit &&
row.empty_bits[column->empty_pos] & column->empty_bit))
{ {
if (column->type != FIELD_BLOB) if (column->type != FIELD_BLOB)
*null_field_lengths= 0; *null_field_lengths= 0;

View file

@ -121,7 +121,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
&info.blobs,sizeof(MARIA_BLOB)*share->base.blobs, &info.blobs,sizeof(MARIA_BLOB)*share->base.blobs,
&info.buff,(share->base.max_key_block_length*2+ &info.buff,(share->base.max_key_block_length*2+
share->base.max_key_length), share->base.max_key_length),
&info.lastkey_buff,share->base.max_key_length*2+1, &info.lastkey_buff,share->base.max_key_length*3,
&info.first_mbr_key, share->base.max_key_length, &info.first_mbr_key, share->base.max_key_length,
&info.maria_rtree_recursion_state, &info.maria_rtree_recursion_state,
share->have_rtree ? 1024 : 0, share->have_rtree ? 1024 : 0,

View file

@ -2143,9 +2143,17 @@ int ha_myisam::info(uint flag)
share->keys_for_keyread.intersect(share->keys_in_use); share->keys_for_keyread.intersect(share->keys_in_use);
share->db_record_offset= misam_info.record_offset; share->db_record_offset= misam_info.record_offset;
if (share->key_parts) if (share->key_parts)
memcpy((char*) table->key_info[0].rec_per_key, {
(char*) misam_info.rec_per_key, ulong *from= misam_info.rec_per_key;
sizeof(table->key_info[0].rec_per_key[0])*share->key_parts); KEY *key, *key_end;
for (key= table->key_info, key_end= key + share->keys;
key < key_end ; key++)
{
memcpy(key->rec_per_key, from,
key->user_defined_key_parts * sizeof(*from));
from+= key->user_defined_key_parts;
}
}
if (table_share->tmp_table == NO_TMP_TABLE) if (table_share->tmp_table == NO_TMP_TABLE)
mysql_mutex_unlock(&table_share->LOCK_share); mysql_mutex_unlock(&table_share->LOCK_share);
} }