diff --git a/mysql-test/lib/v1/mysql-test-run.pl b/mysql-test/lib/v1/mysql-test-run.pl index 5671f58bbfe..a47d58a5180 100755 --- a/mysql-test/lib/v1/mysql-test-run.pl +++ b/mysql-test/lib/v1/mysql-test-run.pl @@ -5285,7 +5285,6 @@ sub valgrind_arguments { else { mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option - mtr_add_arg($args, "--alignment=8"); mtr_add_arg($args, "--leak-check=yes"); mtr_add_arg($args, "--num-callers=16"); mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) diff --git a/mysql-test/suite/maria/r/small_blocksize.result b/mysql-test/suite/maria/r/small_blocksize.result new file mode 100644 index 00000000000..41d9a561a4d --- /dev/null +++ b/mysql-test/suite/maria/r/small_blocksize.result @@ -0,0 +1,75 @@ +DROP TABLE if exists t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (col_longtext_ucs2 longtext, col_longtext_utf8 longtext, col_varchar_255_ucs2_key varchar(255), col_set_utf8 set ('a','b'), col_char_255_ucs2 char(255), col_char_255_ucs2_key char(255), col_enum_ucs2 enum ('a','b'), col_varchar_255_ucs2 varchar(255), col_longtext_ucs2_key longtext, col_longtext_utf8_key longtext, col_enum_utf8 enum ('a','b'), col_varchar_255_utf8_key varchar(1024), col_varchar_255_utf8 varchar(255), col_enum_ucs2_key enum ('a','b'), col_enum_utf8_key enum ('a','b'), col_set_utf8_key set ('a','b'), col_char_255_utf8 char(255), pk integer auto_increment, col_set_ucs2_key set ('a','b'), col_char_255_utf8_key char(255), col_set_ucs2 set ('a','b'), primary key (pk)) ENGINE=aria; +INSERT INTO t1 ( col_char_255_utf8, col_varchar_255_utf8_key, col_longtext_utf8_key ) VALUES ( 'lggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrk', REPEAT( 'a', 627 ), 'mlggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrklnipcmzbtwdqfnyinqfohgtiwmvfpbuslgobjhslxnaybcyebhsrlipnuvalhmvhlwbwujtvjsdrbyapfzprnxfgtrukwhywtkaoupsaogxsjxhqjkidvnpeytjgndtnrrbm' ); +UPDATE t1 SET col_varchar_255_utf8 = REPEAT('a', 197 ); +UPDATE t1 SET col_char_255_utf8 = 'bmjihzjtxegprqfvmczyzbavjuozkyxrlxvqyzcfvsjrhcccqnecyohzhzbgsbqkqvzmtlhtlcgzheirkyfwczoolilkrfimfnuoapyylbghdhdgfebjjajfoigagozypqtrflrvdiwfgqalsqbmlllsanvtuuutiaastqtbzeoaawl'; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a int primary key auto_increment, e1 enum('a','b'), e2 enum('a','b'), vl int, bl int, c char(10), v1 varchar(10000), v2 varchar(10000), b1 blob, b2 blob) engine=aria; +insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(5000,5000),(8000,12000); +update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl/2),b1=repeat('c',bl),b2=repeat('d',bl); +insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(1000,5000); +update t1 set c="test", v1=repeat(vl/4,'a'),v2=repeat(vl/5,'b'),b1=repeat(b1*2,'c'),b2=repeat(bl/2,'d'); +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'b' +Warning 1292 Truncated incorrect INTEGER value: 'c' +Warning 1292 Truncated incorrect INTEGER value: 'd' +update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/5),b1=repeat('c',bl*2),b2=repeat('d',bl/2); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl),b1=repeat('c',bl*2),b2=repeat('d',bl/2); +update t1 set c="test", v1=repeat('a',vl/2),v2=repeat('b',vl/2),b1=repeat('c',bl/2),b2=repeat('d',bl/2); +update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/4),b1=repeat('c',bl/4),b2=repeat('d',bl/4); +update t1 set c="test", v1=repeat('a',vl/20),v2=repeat('b',vl),b1=repeat('c',bl/20),b2=repeat('d',bl/20); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl/100),b1=repeat('c',bl/100); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl),b1=repeat('c',bl); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',10),v2=repeat('b',10); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',2000),v2=repeat('b',2000); +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; diff --git a/mysql-test/suite/maria/t/small_blocksize-master.opt b/mysql-test/suite/maria/t/small_blocksize-master.opt new file mode 100644 index 00000000000..59fd35a7846 --- /dev/null +++ b/mysql-test/suite/maria/t/small_blocksize-master.opt @@ -0,0 +1 @@ +--aria-block-size=1024 diff --git a/mysql-test/suite/maria/t/small_blocksize.test b/mysql-test/suite/maria/t/small_blocksize.test new file mode 100644 index 00000000000..673558e6b20 --- /dev/null +++ b/mysql-test/suite/maria/t/small_blocksize.test @@ -0,0 +1,35 @@ +DROP TABLE if exists t1; + +# +# Test of extending updated rows. +# This caused failures in lp:815022 +# +CREATE TABLE t1 (col_longtext_ucs2 longtext, col_longtext_utf8 longtext, col_varchar_255_ucs2_key varchar(255), col_set_utf8 set ('a','b'), col_char_255_ucs2 char(255), col_char_255_ucs2_key char(255), col_enum_ucs2 enum ('a','b'), col_varchar_255_ucs2 varchar(255), col_longtext_ucs2_key longtext, col_longtext_utf8_key longtext, col_enum_utf8 enum ('a','b'), col_varchar_255_utf8_key varchar(1024), col_varchar_255_utf8 varchar(255), col_enum_ucs2_key enum ('a','b'), col_enum_utf8_key enum ('a','b'), col_set_utf8_key set ('a','b'), col_char_255_utf8 char(255), pk integer auto_increment, col_set_ucs2_key set ('a','b'), col_char_255_utf8_key char(255), col_set_ucs2 set ('a','b'), primary key (pk)) ENGINE=aria; +INSERT INTO t1 ( col_char_255_utf8, col_varchar_255_utf8_key, col_longtext_utf8_key ) VALUES ( 'lggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrk', REPEAT( 'a', 627 ), 'mlggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrklnipcmzbtwdqfnyinqfohgtiwmvfpbuslgobjhslxnaybcyebhsrlipnuvalhmvhlwbwujtvjsdrbyapfzprnxfgtrukwhywtkaoupsaogxsjxhqjkidvnpeytjgndtnrrbm' ); +UPDATE t1 SET col_varchar_255_utf8 = REPEAT('a', 197 ); +UPDATE t1 SET col_char_255_utf8 = 'bmjihzjtxegprqfvmczyzbavjuozkyxrlxvqyzcfvsjrhcccqnecyohzhzbgsbqkqvzmtlhtlcgzheirkyfwczoolilkrfimfnuoapyylbghdhdgfebjjajfoigagozypqtrflrvdiwfgqalsqbmlllsanvtuuutiaastqtbzeoaawl'; +check table t1; +drop table t1; + +create table t1 (a int primary key auto_increment, e1 enum('a','b'), e2 enum('a','b'), vl int, bl int, c char(10), v1 varchar(10000), v2 varchar(10000), b1 blob, b2 blob) engine=aria; + +insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(5000,5000),(8000,12000); +update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl/2),b1=repeat('c',bl),b2=repeat('d',bl); +insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(1000,5000); +update t1 set c="test", v1=repeat(vl/4,'a'),v2=repeat(vl/5,'b'),b1=repeat(b1*2,'c'),b2=repeat(bl/2,'d'); +update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/5),b1=repeat('c',bl*2),b2=repeat('d',bl/2); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl),b1=repeat('c',bl*2),b2=repeat('d',bl/2); +update t1 set c="test", v1=repeat('a',vl/2),v2=repeat('b',vl/2),b1=repeat('c',bl/2),b2=repeat('d',bl/2); +update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/4),b1=repeat('c',bl/4),b2=repeat('d',bl/4); +update t1 set c="test", v1=repeat('a',vl/20),v2=repeat('b',vl),b1=repeat('c',bl/20),b2=repeat('d',bl/20); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl/100),b1=repeat('c',bl/100); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',vl),b1=repeat('c',bl); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',10),v2=repeat('b',10); +insert into t1 (vl,bl) values (100,100); +update t1 set c="test", v1=repeat('a',2000),v2=repeat('b',2000); +check table t1; +drop table t1; diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 58264513da9..33609afcb9b 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -874,7 +874,7 @@ double ha_maria::scan_time() } /* - We need to be able to store at least two keys on an index page as the + We need to be able to store at least 2 keys on an index page as the splitting algorithms depends on this. (With only one key on a page we also can't use any compression, which may make the index file much larger) diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c index ac3d23b7079..a98ef71604d 100644 --- a/storage/maria/ma_bitmap.c +++ b/storage/maria/ma_bitmap.c @@ -1853,7 +1853,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size, find_where_to_split_row() share Maria share row Information of what is in the row (from calc_record_size()) - extents_length Number of bytes needed to store all extents + extents Max number of extents we have to store in header split_size Free size on the page (The head length must be less than this) @@ -1862,7 +1862,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size, */ static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row, - uint extents_length, uint split_size) + uint extents, uint split_size) { uint *lengths, *lengths_end; /* @@ -1872,19 +1872,20 @@ static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row, - One extent */ uint row_length= (row->min_length + - size_to_store_key_length(extents_length) + + size_to_store_key_length(extents) + ROW_EXTENT_SIZE); - DBUG_ASSERT(row_length < split_size); + DBUG_ASSERT(row_length <= split_size); + /* Store first in all_field_lengths the different parts that are written to the row. This needs to be in same order as in ma_block_rec.c::write_block_record() */ - row->null_field_lengths[-3]= extents_length; + row->null_field_lengths[-3]= extents * ROW_EXTENT_SIZE; row->null_field_lengths[-2]= share->base.fixed_not_null_fields_length; row->null_field_lengths[-1]= row->field_lengths_length; for (lengths= row->null_field_lengths - EXTRA_LENGTH_FIELDS, - lengths_end= (lengths + share->base.pack_fields - share->base.blobs + + lengths_end= (lengths + share->base.fields - share->base.blobs + EXTRA_LENGTH_FIELDS); lengths < lengths_end; lengths++) { if (row_length + *lengths > split_size) @@ -2040,18 +2041,19 @@ my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row, head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE; /* The first segment size is stored in 'row_length' */ - row_length= find_where_to_split_row(share, row, extents_length, + row_length= find_where_to_split_row(share, row, row->extents_count + + ELEMENTS_RESERVED_FOR_MAIN_PART-1, max_page_size); full_page_size= MAX_TAIL_SIZE(share->block_size); position= 0; - if (head_length - row_length <= full_page_size) + rest_length= head_length - row_length; + if (rest_length <= full_page_size) position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */ if (find_head(info, row_length, position)) goto abort; row->space_on_head_page= row_length; - rest_length= head_length - row_length; if (write_rest_of_head(info, position, rest_length)) goto abort; @@ -2137,16 +2139,22 @@ my_bool _ma_bitmap_find_new_place(MARIA_HA *info, MARIA_ROW *row, /* Allocate enough space */ head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE; - /* The first segment size is stored in 'row_length' */ - row_length= find_where_to_split_row(share, row, extents_length, free_size); + /* + The first segment size is stored in 'row_length' + We have to add ELEMENTS_RESERVED_FOR_MAIN_PART here as the extent + information may be up to this size when the header splits. + */ + row_length= find_where_to_split_row(share, row, row->extents_count + + ELEMENTS_RESERVED_FOR_MAIN_PART-1, + free_size); position= 0; - if (head_length - row_length < MAX_TAIL_SIZE(share->block_size)) + rest_length= head_length - row_length; + if (rest_length <= MAX_TAIL_SIZE(share->block_size)) position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */ use_head(info, page, row_length, position); row->space_on_head_page= row_length; - rest_length= head_length - row_length; if (write_rest_of_head(info, position, rest_length)) goto abort; diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 36cd63667e7..ad5ec3fe2b9 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -1721,7 +1721,7 @@ struct st_row_pos_info static my_bool get_head_or_tail_page(MARIA_HA *info, - MARIA_BITMAP_BLOCK *block, + const MARIA_BITMAP_BLOCK *block, uchar *buff, uint length, uint page_type, enum pagecache_page_lock lock, struct st_row_pos_info *res) @@ -1821,7 +1821,7 @@ crashed: */ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info, - MARIA_BITMAP_BLOCK *block, + const MARIA_BITMAP_BLOCK *block, uchar *buff, uint length, uint page_type, enum pagecache_page_lock lock, @@ -2257,7 +2257,7 @@ static void store_extent_info(uchar *to, for (block= first_block, end_block= first_block+count ; block < end_block; block++) { - /* The following is only false for marker blocks */ + /* The following is only false for marker (unused) blocks */ if (likely(block->used & BLOCKUSED_USED)) { uint page_count= block->page_count; @@ -3088,9 +3088,10 @@ static my_bool write_block_record(MARIA_HA *info, extent_data= row_extents_second_part + ((last_head_block - head_block) - 2) * ROW_EXTENT_SIZE; } - DBUG_ASSERT(uint2korr(extent_data+5) & TAIL_BIT); + /* Write information for tail block in the reserved space */ page_store(extent_data, head_tail_block->page); - int2store(extent_data + PAGE_STORE_SIZE, head_tail_block->page_count); + pagerange_store(extent_data + PAGE_STORE_SIZE, + head_tail_block->page_count); } } else diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h index 2a323d16ffa..45f5613bb60 100644 --- a/storage/maria/ma_blockrec.h +++ b/storage/maria/ma_blockrec.h @@ -59,7 +59,6 @@ /* Minimum header size needed for a new row */ #define BASE_ROW_HEADER_SIZE FLAG_SIZE -#define TRANS_ROW_EXTRA_HEADER_SIZE TRANSID_SIZE #define PAGE_TYPE_MASK 7 enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE }; diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c index ab66499ecfe..a4e485066f5 100644 --- a/storage/maria/ma_delete.c +++ b/storage/maria/ma_delete.c @@ -571,6 +571,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key, endpos= leaf_page->buff + leaf_length; tmp_key.keyinfo= keyinfo; tmp_key.data= keybuff; + next_buff= 0; if (!(key_start= _ma_get_last_key(&tmp_key, leaf_page, endpos))) DBUG_RETURN(-1); @@ -597,9 +598,11 @@ static int del(MARIA_HA *info, MARIA_KEY *key, /* underflow writes "next_page" to disk */ ret_value= underflow(info, keyinfo, leaf_page, &next_page, endpos); - if (ret_value == 0 && leaf_page->size > - share->max_index_block_size) + if (ret_value < 0) + goto err; + if (leaf_page->size > share->max_index_block_size) { + DBUG_ASSERT(ret_value == 0); ret_value= (_ma_split_page(info, key, leaf_page, share->max_index_block_size, (uchar*) 0, 0, 0, @@ -632,6 +635,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key, goto err; } my_afree(next_buff); + DBUG_ASSERT(leaf_page->size <= share->max_index_block_size); DBUG_RETURN(ret_value); } @@ -709,10 +713,14 @@ static int del(MARIA_HA *info, MARIA_KEY *key, KEY_OP_DEBUG_LOG_ADD_2)) goto err; + DBUG_ASSERT(leaf_page->size <= share->max_index_block_size); DBUG_RETURN(new_leaf_length <= (info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH : (uint) keyinfo->underflow_block_length)); err: + if (next_buff) + my_afree(next_buff); + DBUG_RETURN(-1); } /* del */ @@ -731,9 +739,18 @@ err: leaf_page is saved to disk Caller must save anc_buff + For the algoritm to work, we have to ensure for packed keys that + key_length + (underflow_length + max_block_length + key_length) / 2 + <= block_length. + From which follows that underflow_length <= block_length - key_length *3 + For not packed keys we have: + (underflow_length + max_block_length + key_length) / 2 <= block_length + From which follows that underflow_length < block_length - key_length + This is ensured by setting of underflow_block_length. + @return @retval 0 ok - @retval 1 ok, but anc_buff did underflow + @retval 1 ok, but anc_page did underflow @retval -1 error */ @@ -1153,7 +1170,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, _ma_kpointer(info,leaf_key.data + leaf_key.data_length + leaf_key.ref_length, leaf_page->pos); - /* Save key in anc_page */ + /* Save parting key found by _ma_find_half_pos() in anc_page */ DBUG_DUMP("anc_buff", anc_buff, new_anc_length); DBUG_DUMP_KEY("key_to_anc", &leaf_key); anc_end_pos= anc_buff + new_anc_length; @@ -1191,6 +1208,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, bmove(leaf_buff+p_length+t_length, half_pos, tmp_length); (*keyinfo->store_key)(keyinfo,leaf_buff+p_length, &key_inserted); new_leaf_length= tmp_length + t_length + p_length; + DBUG_ASSERT(new_leaf_length <= share->max_index_block_size); leaf_page->size= new_leaf_length; leaf_page->flag= page_flag; @@ -1232,7 +1250,6 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, /* Log changes to next page This contains original data with some suffix data deleted - */ DBUG_ASSERT(new_buff_length <= buff_length); if (_ma_log_suffix(&next_page, buff_length, new_buff_length)) diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index f9ec70499f1..498904f89a7 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -563,21 +563,40 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) share->block_size= share->base.block_size; /* Convenience */ share->max_index_block_size= share->block_size - KEYPAGE_CHECKSUM_SIZE; + share->keypage_header= ((share->base.born_transactional ? + LSN_STORE_SIZE + TRANSID_SIZE : + 0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE + + KEYPAGE_USED_SIZE); { HA_KEYSEG *pos=share->keyparts; uint32 ftkey_nr= 1; for (i=0 ; i < keys ; i++) { - share->keyinfo[i].share= share; - disk_pos=_ma_keydef_read(disk_pos, &share->keyinfo[i]); - share->keyinfo[i].key_nr= i; + MARIA_KEYDEF *keyinfo= &share->keyinfo[i]; + keyinfo->share= share; + disk_pos=_ma_keydef_read(disk_pos, keyinfo); + keyinfo->key_nr= i; + + /* See ma_delete.cc::underflow() */ + if (!(keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY))) + keyinfo->underflow_block_length= keyinfo->block_length/3; + else + { + /* Packed key, ensure we don't get overflow in underflow() */ + keyinfo->underflow_block_length= + max((int) (share->max_index_block_size - keyinfo->maxlength * 3), + (int) (share->keypage_header + share->base.key_reflength)); + set_if_smaller(keyinfo->underflow_block_length, + keyinfo->block_length/3); + } + disk_pos_assert(share, - disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE, + disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE, end_pos); - if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE) + if (keyinfo->key_alg == HA_KEY_ALG_RTREE) share->have_rtree= 1; - share->keyinfo[i].seg=pos; - for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) + keyinfo->seg=pos; + for (j=0 ; j < keyinfo->keysegs; j++,pos++) { disk_pos=_ma_keyseg_read(disk_pos, pos); if (pos->type == HA_KEYTYPE_TEXT || @@ -595,25 +614,25 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) else if (pos->type == HA_KEYTYPE_BINARY) pos->charset= &my_charset_bin; } - if (share->keyinfo[i].flag & HA_SPATIAL) + if (keyinfo->flag & HA_SPATIAL) { #ifdef HAVE_SPATIAL uint sp_segs=SPDIMS*2; - share->keyinfo[i].seg=pos-sp_segs; - share->keyinfo[i].keysegs--; + keyinfo->seg=pos-sp_segs; + keyinfo->keysegs--; versioning= 0; #else my_errno=HA_ERR_UNSUPPORTED; goto err; #endif } - else if (share->keyinfo[i].flag & HA_FULLTEXT) + else if (keyinfo->flag & HA_FULLTEXT) { versioning= 0; DBUG_ASSERT(fulltext_keys); { uint k; - share->keyinfo[i].seg=pos; + keyinfo->seg=pos; for (k=0; k < FT_SEGS; k++) { *pos= ft_keysegs[k]; @@ -628,8 +647,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) } if (!share->ft2_keyinfo.seg) { - memcpy(&share->ft2_keyinfo, &share->keyinfo[i], - sizeof(MARIA_KEYDEF)); + memcpy(&share->ft2_keyinfo, keyinfo, sizeof(MARIA_KEYDEF)); share->ft2_keyinfo.keysegs=1; share->ft2_keyinfo.flag=0; share->ft2_keyinfo.keylength= @@ -639,10 +657,10 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) share->ft2_keyinfo.end=pos; setup_key_functions(& share->ft2_keyinfo); } - share->keyinfo[i].ftkey_nr= ftkey_nr++; + keyinfo->ftkey_nr= ftkey_nr++; } - setup_key_functions(share->keyinfo+i); - share->keyinfo[i].end=pos; + setup_key_functions(keyinfo); + keyinfo->end=pos; pos->type=HA_KEYTYPE_END; /* End */ pos->length=share->base.rec_reflength; pos->null_bit=0; @@ -686,10 +704,6 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) share->base.null_bytes + share->base.pack_bytes + test(share->options & HA_OPTION_CHECKSUM)); - share->keypage_header= ((share->base.born_transactional ? - LSN_STORE_SIZE + TRANSID_SIZE : - 0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE + - KEYPAGE_USED_SIZE); share->kfile.file= kfile; if (open_flags & HA_OPEN_COPY) @@ -1580,7 +1594,6 @@ uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef) keydef->keylength = mi_uint2korr(ptr); ptr+= 2; keydef->minlength = mi_uint2korr(ptr); ptr+= 2; keydef->maxlength = mi_uint2korr(ptr); ptr+= 2; - keydef->underflow_block_length=keydef->block_length/3; keydef->version = 0; /* Not saved */ keydef->parser = &ft_default_parser; keydef->ftkey_nr = 0; diff --git a/storage/maria/ma_page.c b/storage/maria/ma_page.c index bcd50f028ec..9f6a7406ea7 100644 --- a/storage/maria/ma_page.c +++ b/storage/maria/ma_page.c @@ -193,6 +193,7 @@ my_bool _ma_write_keypage(MARIA_PAGE *page, enum pagecache_page_lock lock, nod_flag= _ma_test_if_nod(share, buff); DBUG_ASSERT(page->size == page_length); + DBUG_ASSERT(page->size <= share->max_index_block_size); DBUG_ASSERT(page->flag == _ma_get_keypage_flag(share, buff)); if (page->pos < share->base.keystart || diff --git a/storage/maria/ma_write.c b/storage/maria/ma_write.c index 9a6f2f1a440..629e07b872d 100644 --- a/storage/maria/ma_write.c +++ b/storage/maria/ma_write.c @@ -1068,7 +1068,6 @@ int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, MARIA_PAGE *split_page, Returns pointer to start of key. key will contain the key. - return_key_length will contain the length of key after_key will contain the position to where the next key starts */ diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 8ac33c51cc1..dcdb500f3a5 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -740,7 +740,7 @@ struct st_maria_handler { length=mi_uint2korr((key)+1)+3; } \ } -#define maria_max_key_length() ((maria_block_size - MAX_KEYPAGE_HEADER_SIZE)/2 - MARIA_INDEX_OVERHEAD_SIZE) +#define maria_max_key_length() ((maria_block_size - MAX_KEYPAGE_HEADER_SIZE)/3 - MARIA_INDEX_OVERHEAD_SIZE) #define get_pack_length(length) ((length) >= 255 ? 3 : 1) #define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)