diff options
32 files changed, 709 insertions, 102 deletions
diff --git a/myisam/mi_check.c b/myisam/mi_check.c index c4df81c7ca9..05e50022120 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -250,11 +250,12 @@ static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr) my_off_t next_link; uint block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH; ha_rows records; - char llbuff[21],*buff; + char llbuff[21], llbuff2[21], *buff; DBUG_ENTER("check_k_link"); + DBUG_PRINT("enter", ("block_size: %u", block_size)); if (param->testflag & T_VERBOSE) - printf("block_size %4d:",block_size); + printf("block_size %4u:", block_size); /* purecov: tested */ next_link=info->s->state.key_del[nr]; records= (ha_rows) (info->state->key_file_length / block_size); @@ -264,14 +265,46 @@ static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr) DBUG_RETURN(1); if (param->testflag & T_VERBOSE) printf("%16s",llstr(next_link,llbuff)); - if (next_link > info->state->key_file_length || - next_link & (info->s->blocksize-1)) + + /* Key blocks must lay within the key file length entirely. */ + if (next_link + block_size > info->state->key_file_length) + { + /* purecov: begin tested */ + mi_check_print_error(param, "Invalid key block position: %s " + "key block size: %u file_length: %s", + llstr(next_link, llbuff), block_size, + llstr(info->state->key_file_length, llbuff2)); + DBUG_RETURN(1); + /* purecov: end */ + } + + /* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */ + if (next_link & (MI_MIN_KEY_BLOCK_LENGTH - 1)) + { + /* purecov: begin tested */ + mi_check_print_error(param, "Mis-aligned key block: %s " + "minimum key block length: %u", + llstr(next_link, llbuff), MI_MIN_KEY_BLOCK_LENGTH); DBUG_RETURN(1); + /* purecov: end */ + } + + /* + Read the key block with MI_MIN_KEY_BLOCK_LENGTH to find next link. + If the key cache block size is smaller than block_size, we can so + avoid unecessary eviction of cache block. + */ if (!(buff=key_cache_read(info->s->key_cache, info->s->kfile, next_link, DFLT_INIT_HITS, - (byte*) info->buff, - myisam_block_size, block_size, 1))) + (byte*) info->buff, MI_MIN_KEY_BLOCK_LENGTH, + MI_MIN_KEY_BLOCK_LENGTH, 1))) + { + /* purecov: begin tested */ + mi_check_print_error(param, "key cache read error for block: %s", + llstr(next_link,llbuff)); DBUG_RETURN(1); + /* purecov: end */ + } next_link=mi_sizekorr(buff); records--; param->key_file_blocks+=block_size; @@ -555,17 +588,37 @@ static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, ha_checksum *key_checksum, uint level) { char llbuff[22],llbuff2[22]; - if (page > info->state->key_file_length || (page & (info->s->blocksize -1))) - { - my_off_t max_length=my_seek(info->s->kfile,0L,MY_SEEK_END,MYF(0)); - mi_check_print_error(param,"Wrong pagepointer: %s at page: %s", - llstr(page,llbuff),llstr(page,llbuff2)); - - if (page+info->s->blocksize > max_length) + DBUG_ENTER("chk_index_down"); + + /* Key blocks must lay within the key file length entirely. */ + if (page + keyinfo->block_length > info->state->key_file_length) + { + /* purecov: begin tested */ + /* Give it a chance to fit in the real file size. */ + my_off_t max_length= my_seek(info->s->kfile, 0L, MY_SEEK_END, MYF(0)); + mi_check_print_error(param, "Invalid key block position: %s " + "key block size: %u file_length: %s", + llstr(page, llbuff), keyinfo->block_length, + llstr(info->state->key_file_length, llbuff2)); + if (page + keyinfo->block_length > max_length) goto err; - info->state->key_file_length=(max_length & - ~ (my_off_t) (info->s->blocksize-1)); + /* Fix the remebered key file length. */ + info->state->key_file_length= (max_length & + ~ (my_off_t) (keyinfo->block_length - 1)); + /* purecov: end */ + } + + /* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */ + if (page & (MI_MIN_KEY_BLOCK_LENGTH - 1)) + { + /* purecov: begin tested */ + mi_check_print_error(param, "Mis-aligned key block: %s " + "minimum key block length: %u", + llstr(page, llbuff), MI_MIN_KEY_BLOCK_LENGTH); + goto err; + /* purecov: end */ } + if (!_mi_fetch_keypage(info,keyinfo,page, DFLT_INIT_HITS,buff,0)) { mi_check_print_error(param,"Can't read key from filepos: %s", @@ -576,9 +629,12 @@ static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, if (chk_index(param,info,keyinfo,page,buff,keys,key_checksum,level)) goto err; - return 0; + DBUG_RETURN(0); + + /* purecov: begin tested */ err: - return 1; + DBUG_RETURN(1); + /* purecov: end */ } diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index d8aa1ec964c..114bdadf4ef 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1028,9 +1028,11 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from, { uint size_length=rec_length- mi_portable_sizeof_char_ptr; ulong blob_length=_mi_calc_blob_length(size_length,from); - if ((ulong) (from_end-from) - size_length < blob_length || - min_pack_length > (uint) (from_end -(from+size_length+blob_length))) - goto err; + ulong from_left= (ulong) (from_end - from); + if (from_left < size_length || + from_left - size_length < blob_length || + from_left - size_length - blob_length < min_pack_length) + goto err; memcpy((byte*) to,(byte*) from,(size_t) size_length); from+=size_length; memcpy_fixed((byte*) to+size_length,(byte*) &from,sizeof(char*)); diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 25a9411f24d..37614cc1e1f 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -19,7 +19,10 @@ #define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */ -#if INT_MAX > 65536L +/* Some definitions to keep in sync with myisampack.c */ +#define HEAD_LENGTH 32 /* Length of fixed header */ + +#if INT_MAX > 32767 #define BITS_SAVED 32 #define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */ #else @@ -41,6 +44,7 @@ { bits-=(bit+1); break; } \ pos+= *pos +/* Size in uint16 of a Huffman tree for byte compression of 256 byte values. */ #define OFFSET_TABLE_SIZE 512 static uint read_huff_table(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree, @@ -133,7 +137,7 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) uint16 *decode_table,*tmp_buff; ulong elements,intervall_length; char *disk_cache,*intervall_buff; - uchar header[32]; + uchar header[HEAD_LENGTH]; MYISAM_SHARE *share=info->s; MI_BIT_BUFF bit_buff; DBUG_ENTER("_mi_read_pack_info"); @@ -151,12 +155,13 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) my_errno=HA_ERR_END_OF_FILE; goto err0; } + /* Only the first three bytes of magic number are independent of version. */ if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3)) { my_errno=HA_ERR_WRONG_IN_RECORD; goto err0; } - share->pack.version= header[3]; + share->pack.version= header[3]; /* fourth byte of magic number */ share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); @@ -172,7 +177,22 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) share->base.min_block_length=share->min_pack_length+1; if (share->min_pack_length > 254) share->base.min_block_length+=2; - + DBUG_PRINT("info", ("fixed header length: %u", HEAD_LENGTH)); + DBUG_PRINT("info", ("total header length: %lu", share->pack.header_length)); + DBUG_PRINT("info", ("pack file version: %u", share->pack.version)); + DBUG_PRINT("info", ("min pack length: %lu", share->min_pack_length)); + DBUG_PRINT("info", ("max pack length: %lu", share->max_pack_length)); + DBUG_PRINT("info", ("elements of all trees: %lu", elements)); + DBUG_PRINT("info", ("distinct values bytes: %lu", intervall_length)); + DBUG_PRINT("info", ("number of code trees: %u", trees)); + DBUG_PRINT("info", ("bytes for record lgt: %u", share->pack.ref_length)); + DBUG_PRINT("info", ("record pointer length: %u", rec_reflength)); + + /* + Memory segment #1: + - Decode tree heads + - Distinct column values + */ if (!(share->decode_trees=(MI_DECODE_TREE*) my_malloc((uint) (trees*sizeof(MI_DECODE_TREE)+ intervall_length*sizeof(byte)), @@ -180,11 +200,19 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) goto err0; intervall_buff=(byte*) (share->decode_trees+trees); + /* + Memory segment #2: + - Decode tables + - Quick decode tables + - Temporary decode table + - Compressed data file header cache + This segment will be reallocated after construction of the tables. + */ length=(uint) (elements*2+trees*(1 << myisam_quick_table_bits)); if (!(share->decode_tables=(uint16*) - my_malloc((length+OFFSET_TABLE_SIZE)*sizeof(uint16)+ - (uint) (share->pack.header_length+7), - MYF(MY_WME | MY_ZEROFILL)))) + my_malloc((length + OFFSET_TABLE_SIZE) * sizeof(uint16) + + (uint) (share->pack.header_length - sizeof(header)), + MYF(MY_WME | MY_ZEROFILL)))) goto err1; tmp_buff=share->decode_tables+length; disk_cache=(byte*) (tmp_buff+OFFSET_TABLE_SIZE); @@ -197,7 +225,7 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) huff_tree_bits=max_bit(trees ? trees-1 : 0); init_bit_buffer(&bit_buff, (uchar*) disk_cache, (uint) (share->pack.header_length-sizeof(header))); - /* Read new info for each field */ + /* Read new info for each field */ for (i=0 ; i < share->base.fields ; i++) { share->rec[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,5); @@ -206,17 +234,26 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) share->rec[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff, huff_tree_bits); share->rec[i].unpack=get_unpack_function(share->rec+i); + DBUG_PRINT("info", ("col: %2u type: %2u pack: %u slbits: %2u", + i, share->rec[i].base_type, share->rec[i].pack_type, + share->rec[i].space_length_bits)); } skip_to_next_byte(&bit_buff); + /* + Construct the decoding tables from the file header. Keep track of + the used memory. + */ decode_table=share->decode_tables; for (i=0 ; i < trees ; i++) if (read_huff_table(&bit_buff,share->decode_trees+i,&decode_table, &intervall_buff,tmp_buff)) goto err3; + /* Reallocate the decoding tables to the used size. */ decode_table=(uint16*) my_realloc((gptr) share->decode_tables, (uint) ((byte*) decode_table - (byte*) share->decode_tables), MYF(MY_HOLD_ON_ERROR)); + /* Fix the table addresses in the tree heads. */ { long diff=PTR_BYTE_DIFF(decode_table,share->decode_tables); share->decode_tables=decode_table; @@ -225,7 +262,7 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) diff, uint16*); } - /* Fix record-ref-length for keys */ + /* Fix record-ref-length for keys */ if (fix_keys) { for (i=0 ; i < share->base.keys ; i++) @@ -262,7 +299,23 @@ err0: } - /* Read on huff-code-table from datafile */ +/* + Read a huff-code-table from datafile. + + SYNOPSIS + read_huff_table() + bit_buff Bit buffer pointing at start of the + decoding table in the file header cache. + decode_tree Pointer to the decode tree head. + decode_table IN/OUT Address of a pointer to the next free space. + intervall_buff IN/OUT Address of a pointer to the next unused values. + tmp_buff Buffer for temporary extraction of a full + decoding table as read from bit_buff. + + RETURN + 0 OK. + 1 Error. +*/ static uint read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree, uint16 **decode_table, byte **intervall_buff, @@ -271,19 +324,32 @@ static uint read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree, uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits, next_free_offset; uint16 *ptr,*end; + DBUG_ENTER("read_huff_table"); - LINT_INIT(ptr); if (!get_bits(bit_buff,1)) { + /* Byte value compression. */ min_chr=get_bits(bit_buff,8); elements=get_bits(bit_buff,9); char_bits=get_bits(bit_buff,5); offset_bits=get_bits(bit_buff,5); intervall_length=0; ptr=tmp_buff; + DBUG_PRINT("info", ("byte value compression")); + DBUG_PRINT("info", ("minimum byte value: %u", min_chr)); + DBUG_PRINT("info", ("number of tree nodes: %u", elements)); + DBUG_PRINT("info", ("bits for values: %u", char_bits)); + DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits)); + if (elements > 256) + { + DBUG_PRINT("error", ("ERROR: illegal number of tree elements: %u", + elements)); + DBUG_RETURN(1); + } } else { + /* Distinct column value compression. */ min_chr=0; elements=get_bits(bit_buff,15); intervall_length=get_bits(bit_buff,16); @@ -291,13 +357,28 @@ static uint read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree, offset_bits=get_bits(bit_buff,5); decode_tree->quick_table_bits=0; ptr= *decode_table; + DBUG_PRINT("info", ("distinct column value compression")); + DBUG_PRINT("info", ("number of tree nodes: %u", elements)); + DBUG_PRINT("info", ("value buffer length: %u", intervall_length)); + DBUG_PRINT("info", ("bits for value index: %u", char_bits)); + DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits)); } size=elements*2-2; + DBUG_PRINT("info", ("tree size in uint16: %u", size)); + DBUG_PRINT("info", ("tree size in bytes: %u", + size * (uint) sizeof(uint16))); for (end=ptr+size ; ptr < end ; ptr++) { if (get_bit(bit_buff)) + { *ptr= (uint16) get_bits(bit_buff,offset_bits); + if ((ptr + *ptr >= end) || !*ptr) + { + DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree")); + DBUG_RETURN(1); + } + } else *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr)); } @@ -307,11 +388,15 @@ static uint read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree, decode_tree->intervalls= *intervall_buff; if (! intervall_length) { - table_bits=find_longest_bitstream(tmp_buff, tmp_buff+OFFSET_TABLE_SIZE); - if (table_bits == (uint) ~0) - return 1; + /* Byte value compression. ptr started from tmp_buff. */ + /* Find longest Huffman code from begin to end of tree in bits. */ + table_bits= find_longest_bitstream(tmp_buff, ptr); + if (table_bits >= OFFSET_TABLE_SIZE) + DBUG_RETURN(1); if (table_bits > myisam_quick_table_bits) table_bits=myisam_quick_table_bits; + DBUG_PRINT("info", ("table bits: %u", table_bits)); + next_free_offset= (1 << table_bits); make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits, table_bits); @@ -320,105 +405,279 @@ static uint read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree, } else { + /* Distinct column value compression. ptr started from *decode_table */ (*decode_table)=end; + /* + get_bits() moves some bytes to a cache buffer in advance. May need + to step back. + */ bit_buff->pos-= bit_buff->bits/8; + /* Copy the distinct column values from the buffer. */ memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length); (*intervall_buff)+=intervall_length; bit_buff->pos+=intervall_length; bit_buff->bits=0; } - return 0; + DBUG_RETURN(0); } +/* + Make a quick_table for faster decoding. + + SYNOPSIS + make_quick_table() + to_table Target quick_table and remaining decode table. + decode_table Source Huffman (sub-)tree within tmp_buff. + next_free_offset IN/OUT Next free offset from to_table. + Starts behind quick_table on the top-level. + value Huffman bits found so far. + bits Remaining bits to be collected. + max_bits Total number of bits to collect (table_bits). + + DESCRIPTION + + The quick table is an array of 16-bit values. There exists one value + for each possible code representable by max_bits (table_bits) bits. + In most cases table_bits is 9. So there are 512 16-bit values. + + If the high-order bit (16) is set (IS_CHAR) then the array slot for + this value is a valid Huffman code for a resulting byte value. + + The low-order 8 bits (1..8) are the resulting byte value. + + Bits 9..14 are the length of the Huffman code for this byte value. + This means so many bits from the input stream were needed to + represent this byte value. The remaining bits belong to later + Huffman codes. This also means that for every Huffman code shorter + than table_bits there are multiple entires in the array, which + differ just in the unused bits. + + If the high-order bit (16) is clear (0) then the remaining bits are + the position of the remaining Huffman decode tree segment behind the + quick table. + + RETURN + void +*/ + static void make_quick_table(uint16 *to_table, uint16 *decode_table, uint *next_free_offset, uint value, uint bits, uint max_bits) { + DBUG_ENTER("make_quick_table"); + + /* + When down the table to the requested maximum, copy the rest of the + Huffman table. + */ if (!bits--) { + /* + Remaining left Huffman tree segment starts behind quick table. + Remaining right Huffman tree segment starts behind left segment. + */ to_table[value]= (uint16) *next_free_offset; - *next_free_offset=copy_decode_table(to_table, *next_free_offset, - decode_table); - return; + /* + Re-construct the remaining Huffman tree segment at + next_free_offset in to_table. + */ + *next_free_offset= copy_decode_table(to_table, *next_free_offset, + decode_table); + DBUG_VOID_RETURN; } + + /* Descent on the left side. Left side bits are clear (0). */ if (!(*decode_table & IS_CHAR)) { - make_quick_table(to_table,decode_table+ *decode_table, - next_free_offset,value,bits,max_bits); + /* Not a leaf. Follow the pointer. */ + make_quick_table(to_table, decode_table + *decode_table, + next_free_offset, value, bits, max_bits); } else - fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table); + { + /* + A leaf. A Huffman code is complete. Fill the quick_table + array for all possible bit strings starting with this Huffman + code. + */ + fill_quick_table(to_table + value, bits, max_bits, (uint) *decode_table); + } + + /* Descent on the right side. Right side bits are set (1). */ decode_table++; value|= (1 << bits); if (!(*decode_table & IS_CHAR)) { - make_quick_table(to_table,decode_table+ *decode_table, - next_free_offset,value,bits,max_bits); + /* Not a leaf. Follow the pointer. */ + make_quick_table(to_table, decode_table + *decode_table, + next_free_offset, value, bits, max_bits); } else - fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table); - return; + { + /* + A leaf. A Huffman code is complete. Fill the quick_table + array for all possible bit strings starting with this Huffman + code. + */ + fill_quick_table(to_table + value, bits, max_bits, (uint) *decode_table); + } + + DBUG_VOID_RETURN; } +/* + Fill quick_table for all possible values starting with this Huffman code. + + SYNOPSIS + fill_quick_table() + table Target quick_table position. + bits Unused bits from max_bits. + max_bits Total number of bits to collect (table_bits). + value The byte encoded by the found Huffman code. + + DESCRIPTION + + Fill the segment (all slots) of the quick_table array with the + resulting value for the found Huffman code. There are as many slots + as there are combinations representable by the unused bits. + + In most cases we use 9 table bits. Assume a 3-bit Huffman code. Then + there are 6 unused bits. Hence we fill 2**6 = 64 slots with the + value. + + RETURN + void +*/ + static void fill_quick_table(uint16 *table, uint bits, uint max_bits, uint value) { uint16 *end; - value|=(max_bits-bits) << 8; - for (end=table+ (1 << bits) ; - table < end ; - *table++ = (uint16) value | IS_CHAR) ; + DBUG_ENTER("fill_quick_table"); + + /* + Bits 1..8 of value represent the decoded byte value. + Bits 9..14 become the length of the Huffman code for this byte value. + Bit 16 flags a valid code (IS_CHAR). + */ + value|= (max_bits - bits) << 8 | IS_CHAR; + + for (end= table + (1 << bits); table < end; table++) + { + *table= (uint16) value; + } + DBUG_VOID_RETURN; } +/* + Reconstruct a decode subtree at the target position. + + SYNOPSIS + copy_decode_table() + to_pos Target quick_table and remaining decode table. + offset Next free offset from to_pos. + decode_table Source Huffman subtree within tmp_buff. + + NOTE + Pointers in the decode tree are relative to the pointers position. + + RETURN + next free offset from to_pos. +*/ + static uint copy_decode_table(uint16 *to_pos, uint offset, uint16 *decode_table) { uint prev_offset; prev_offset= offset; + DBUG_ENTER("copy_decode_table"); + /* Descent on the left side. */ if (!(*decode_table & IS_CHAR)) { + /* Set a pointer to the next target node. */ to_pos[offset]=2; + /* Copy the left hand subtree there. */ offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table); } else { + /* Copy the byte value. */ to_pos[offset]= *decode_table; + /* Step behind this node. */ offset+=2; } - decode_table++; + /* Descent on the right side. */ + decode_table++; if (!(*decode_table & IS_CHAR)) { + /* Set a pointer to the next free target node. */ to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1); + /* Copy the right hand subtree to the entry of that node. */ offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table); } else + { + /* Copy the byte value. */ to_pos[prev_offset+1]= *decode_table; - return offset; + } + DBUG_RETURN(offset); } +/* + Find the length of the longest Huffman code in this table in bits. + + SYNOPSIS + find_longest_bitstream() + table Code (sub-)table start. + end End of code table. + + IMPLEMENTATION + + Recursively follow the branch(es) of the code pair on every level of + the tree until two byte values (and no branch) are found. Add one to + each level when returning back from each recursion stage. + + 'end' is used for error checking only. A clean tree terminates + before reaching 'end'. Hence the exact value of 'end' is not too + important. However having it higher than necessary could lead to + misbehaviour should 'next' jump into the dirty area. + + RETURN + length Length of longest Huffman code in bits. + >= OFFSET_TABLE_SIZE Error, broken tree. It does not end before 'end'. +*/ + static uint find_longest_bitstream(uint16 *table, uint16 *end) { - uint length=1,length2; + uint length= 1; + uint length2; + if (!(*table & IS_CHAR)) { uint16 *next= table + *table; if (next > end || next == table) - return ~0; - length=find_longest_bitstream(next, end)+1; + { + DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree")); + return OFFSET_TABLE_SIZE; + } + length= find_longest_bitstream(next, end) + 1; } table++; if (!(*table & IS_CHAR)) { uint16 *next= table + *table; if (next > end || next == table) - return ~0; - length2=find_longest_bitstream(table+ *table, end)+1; + { + DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree")); + return OFFSET_TABLE_SIZE; + } + length2= find_longest_bitstream(next, end) + 1; length=max(length,length2); } return length; @@ -854,18 +1113,46 @@ static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,uchar *to, bit_buff->pos+=4; bits+=32; } - /* First use info in quick_table */ + /* + First use info in quick_table. + + The quick table is an array of 16-bit values. There exists one + value for each possible code representable by table_bits bits. + In most cases table_bits is 9. So there are 512 16-bit values. + + If the high-order bit (16) is set (IS_CHAR) then the array slot + for this value is a valid Huffman code for a resulting byte value. + + The low-order 8 bits (1..8) are the resulting byte value. + + Bits 9..14 are the length of the Huffman code for this byte value. + This means so many bits from the input stream were needed to + represent this byte value. The remaining bits belong to later + Huffman codes. This also means that for every Huffman code shorter + than table_bits there are multiple entires in the array, which + differ just in the unused bits. + + If the high-order bit (16) is clear (0) then the remaining bits are + the position of the remaining Huffman decode tree segment behind the + quick table. + */ low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and; low_byte=decode_tree->table[low_byte]; if (low_byte & IS_CHAR) { + /* + All Huffman codes of less or equal table_bits length are in the + quick table. This is one of them. + */ *to++ = (low_byte & 255); /* Found char in quick table */ bits-= ((low_byte >> 8) & 31); /* Remove bits used */ } else { /* Map through rest of decode-table */ + /* This means that the Huffman code must be longer than table_bits. */ pos=decode_tree->table+low_byte; bits-=table_bits; + /* NOTE: decode_bytes_test_bit() is a macro wich contains a break !!! */ for (;;) { low_byte=(uint) (bit_buff->current_byte >> (bits-8)); @@ -1091,6 +1378,11 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff, { head_length+= read_pack_length((uint) myisam->s->pack.version, header + head_length, &info->blob_len); + /* + Ensure that the record buffer is big enough for the compressed + record plus all expanded blobs. [We do not have an extra buffer + for the resulting blobs. Sigh.] + */ if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len, rec_buff_p))) return BLOCK_FATAL_ERROR; /* not enough memory */ diff --git a/myisam/mi_range.c b/myisam/mi_range.c index 35b44c92322..6655f5a7de6 100644 --- a/myisam/mi_range.c +++ b/myisam/mi_range.c @@ -170,6 +170,7 @@ static double _mi_search_pos(register MI_INFO *info, uchar *keypos,*buff; double offset; DBUG_ENTER("_mi_search_pos"); + LINT_INIT(max_keynr); if (pos == HA_OFFSET_ERROR) DBUG_RETURN(0.5); diff --git a/myisam/mi_test1.c b/myisam/mi_test1.c index 4664ee5f048..3540ac0f580 100644 --- a/myisam/mi_test1.c +++ b/myisam/mi_test1.c @@ -582,7 +582,7 @@ static struct my_option my_long_options[] = static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) + char *argument __attribute__((unused))) { switch(optid) { case 'a': diff --git a/myisam/mi_write.c b/myisam/mi_write.c index d480c79173e..a93ee42e2c0 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -582,6 +582,7 @@ int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo, my_off_t new_pos; MI_KEY_PARAM s_temp; DBUG_ENTER("mi_split_page"); + LINT_INIT(after_key); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); if (info->s->keyinfo+info->lastinx == keyinfo) diff --git a/myisam/rt_split.c b/myisam/rt_split.c index fdc3e51495c..9f25ee608d8 100644 --- a/myisam/rt_split.c +++ b/myisam/rt_split.c @@ -186,6 +186,10 @@ static int split_rtree_node(SplitStruct *node, int n_entries, int next_node; int i; SplitStruct *end = node + n_entries; + LINT_INIT(a); + LINT_INIT(b); + LINT_INIT(next); + LINT_INIT(next_node); if (all_size < min_size * 2) { diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index d376b277c8a..80ad50b886f 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -677,6 +677,21 @@ ERROR 3D000: No database selected alter table test.t1 rename test.t1; use test; drop table t1; +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) default NULL, + KEY `i1` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP TABLE t1; DROP TABLE IF EXISTS bug24219; DROP TABLE IF EXISTS bug24219_2; CREATE TABLE bug24219 (a INT, INDEX(a)); diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 2b44fc8bd7e..cecffbb1471 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -1815,6 +1815,34 @@ engine = federated connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/test'; drop table federated.test1, federated.test2; drop table federated.test; +set names utf8; +create table federated.t1 (a varchar(64)) DEFAULT CHARSET=utf8; +insert into federated.t1 values (0x6DC3A56E6164); +select hex(a) from federated.t1; +hex(a) +6DC3A56E6164 +create table federated.t1 (a varchar(64)) +ENGINE=FEDERATED +connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1' +DEFAULT CHARSET=utf8; +set names utf8; +select hex(a) from federated.t1; +hex(a) +6DC3A56E6164 +insert into federated.t1 values (0xC3A4C3B6C3BCC39F); +insert into federated.t1 values (0xD18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E); +select hex(a) from federated.t1; +hex(a) +6DC3A56E6164 +C3A4C3B6C3BCC39F +D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E +select hex(a) from federated.t1; +hex(a) +6DC3A56E6164 +C3A4C3B6C3BCC39F +D18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E +drop table federated.t1; +drop table federated.t1; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index 3f3360e2da0..9456b4ec978 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -284,7 +284,7 @@ NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 1 -2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where +2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where; Using index create table t3 like t0; insert into t3 select * from t0; alter table t3 add key9 int not null, add index i9(key9); diff --git a/mysql-test/r/index_merge_ror.result b/mysql-test/r/index_merge_ror.result index 69cd11d1dbf..5d08125be53 100644 --- a/mysql-test/r/index_merge_ror.result +++ b/mysql-test/r/index_merge_ror.result @@ -194,3 +194,14 @@ explain select a from t2 where a='ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 6 const 1 Using where drop table t2; +CREATE TABLE t1(c1 INT, c2 INT DEFAULT 0, c3 CHAR(255) DEFAULT '', +KEY(c1), KEY(c2), KEY(c3)); +INSERT INTO t1(c1) VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0), +(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); +INSERT INTO t1 VALUES(0,0,0); +CREATE TABLE t2(c1 int); +INSERT INTO t2 VALUES(1); +DELETE t1 FROM t1,t2 WHERE t1.c1=0 AND t1.c2=0; +SELECT * FROM t1; +c1 c2 c3 +DROP TABLE t1,t2; diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result index 12ffc8437db..670fbe5b4e0 100644 --- a/mysql-test/r/ndb_index_unique.result +++ b/mysql-test/r/ndb_index_unique.result @@ -133,6 +133,21 @@ a b c 6 7 2 7 8 3 8 2 3 +create unique index bi using hash on t2(b); +insert into t2 values(9, 3, 1); +ERROR 23000: Duplicate entry '' for key 0 +alter table t2 drop index bi; +insert into t2 values(9, 3, 1); +select * from t2 order by a; +a b c +2 3 5 +3 4 6 +4 5 8 +5 6 2 +6 7 2 +7 8 3 +8 2 3 +9 3 1 drop table t2; CREATE TABLE t2 ( a int unsigned NOT NULL PRIMARY KEY, diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 233726ce923..d2c9926c422 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -500,6 +500,17 @@ use test; drop table t1; # +# BUG#23404 - ROW_FORMAT=FIXED option is lost is an index is added to the +# table +# +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# # Bug#24219 - ALTER TABLE ... RENAME TO ... , DISABLE KEYS leads to crash # --disable_warnings diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index c2218b3451b..894cd513914 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1544,4 +1544,36 @@ drop table federated.test1, federated.test2; connection slave; drop table federated.test; +# +# BUG# 17044 Federated Storage Engine not UTF8 clean +# +connection slave; +set names utf8; +create table federated.t1 (a varchar(64)) DEFAULT CHARSET=utf8; + +insert into federated.t1 values (0x6DC3A56E6164); +select hex(a) from federated.t1; + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t1 (a varchar(64)) +ENGINE=FEDERATED +connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1' +DEFAULT CHARSET=utf8; +set names utf8; +select hex(a) from federated.t1; +insert into federated.t1 values (0xC3A4C3B6C3BCC39F); +insert into federated.t1 values (0xD18DD184D184D0B5D0BAD182D0B8D0B2D0BDD183D18E); +select hex(a) from federated.t1; + +connection slave; +select hex(a) from federated.t1; + +connection master; +drop table federated.t1; + +connection slave; +drop table federated.t1; + + source include/federated_cleanup.inc; diff --git a/mysql-test/t/index_merge_ror.test b/mysql-test/t/index_merge_ror.test index 48fe5526f11..a9de2f955ee 100644 --- a/mysql-test/t/index_merge_ror.test +++ b/mysql-test/t/index_merge_ror.test @@ -250,3 +250,18 @@ select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA'; insert into t2 values ('ab', 'ab', 'uh', 'oh'); explain select a from t2 where a='ab'; drop table t2; + +# +# BUG#25048 - ERROR 126 : Incorrect key file for table '.XXXX.MYI'; try to +# repair it +# +CREATE TABLE t1(c1 INT, c2 INT DEFAULT 0, c3 CHAR(255) DEFAULT '', +KEY(c1), KEY(c2), KEY(c3)); +INSERT INTO t1(c1) VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0), +(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0); +INSERT INTO t1 VALUES(0,0,0); +CREATE TABLE t2(c1 int); +INSERT INTO t2 VALUES(1); +DELETE t1 FROM t1,t2 WHERE t1.c1=0 AND t1.c2=0; +SELECT * FROM t1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/ndb_index_unique.test b/mysql-test/t/ndb_index_unique.test index e210491c9d0..18eec046074 100644 --- a/mysql-test/t/ndb_index_unique.test +++ b/mysql-test/t/ndb_index_unique.test @@ -83,6 +83,14 @@ delete from t2 where a = 1; insert into t2 values(8, 2, 3); select * from t2 order by a; +# Bug #24818 CREATE UNIQUE INDEX (...) USING HASH on a NDB table crashes mysqld +create unique index bi using hash on t2(b); +-- error 1062 +insert into t2 values(9, 3, 1); +alter table t2 drop index bi; +insert into t2 values(9, 3, 1); +select * from t2 order by a; + drop table t2; CREATE TABLE t2 ( diff --git a/ndb/include/logger/FileLogHandler.hpp b/ndb/include/logger/FileLogHandler.hpp index be018d10102..36a35399ac8 100644 --- a/ndb/include/logger/FileLogHandler.hpp +++ b/ndb/include/logger/FileLogHandler.hpp @@ -101,7 +101,7 @@ private: bool setMaxFiles(const BaseString &files); int m_maxNoFiles; - long m_maxFileSize; + off_t m_maxFileSize; unsigned int m_maxLogEntries; File_class* m_pLogFile; }; diff --git a/ndb/include/util/File.hpp b/ndb/include/util/File.hpp index c62a9cdeac2..b9d348683ec 100644 --- a/ndb/include/util/File.hpp +++ b/ndb/include/util/File.hpp @@ -49,7 +49,7 @@ public: * @param f a pointer to a FILE descriptor. * @return the size of the file. */ - static long size(FILE* f); + static off_t size(FILE* f); /** * Renames a file. @@ -181,7 +181,7 @@ public: * * @return the file size. */ - long size() const; + off_t size() const; /** * Returns the filename. diff --git a/ndb/include/util/Vector.hpp b/ndb/include/util/Vector.hpp index 4d4c71885b7..aeddbbb22f0 100644 --- a/ndb/include/util/Vector.hpp +++ b/ndb/include/util/Vector.hpp @@ -93,6 +93,8 @@ void Vector<T>::push_back(const T & t){ if(m_size == m_arraySize){ T * tmp = new T [m_arraySize + m_incSize]; + if(!tmp) + abort(); for (unsigned k = 0; k < m_size; k++) tmp[k] = m_items[k]; delete[] m_items; diff --git a/ndb/src/common/logger/FileLogHandler.cpp b/ndb/src/common/logger/FileLogHandler.cpp index 015b55b7a94..a4f610777eb 100644 --- a/ndb/src/common/logger/FileLogHandler.cpp +++ b/ndb/src/common/logger/FileLogHandler.cpp @@ -124,8 +124,6 @@ FileLogHandler::writeFooter() } callCount++; - // Needed on Cello since writes to the flash disk does not happen until - // we flush and fsync. m_pLogFile->flush(); } diff --git a/ndb/src/common/util/File.cpp b/ndb/src/common/util/File.cpp index bf100944cb9..23bf3415df9 100644 --- a/ndb/src/common/util/File.cpp +++ b/ndb/src/common/util/File.cpp @@ -44,17 +44,16 @@ File_class::exists(const char* aFileName) return (my_stat(aFileName, &stmp, MYF(0))!=NULL); } -long +off_t File_class::size(FILE* f) { - long cur_pos = 0, length = 0; - - cur_pos = ::ftell(f); - ::fseek(f, 0, SEEK_END); - length = ::ftell(f); - ::fseek(f, cur_pos, SEEK_SET); // restore original position + MY_STAT s; + + // Note that my_fstat behaves *differently* than my_stat. ARGGGHH! + if(my_fstat(::fileno(f), &s, MYF(0))) + return 0; - return length; + return s.st_size; } bool @@ -179,8 +178,8 @@ File_class::writeChar(const char* buf) { return writeChar(buf, 0, ::strlen(buf)); } - -long + +off_t File_class::size() const { return File_class::size(m_file); @@ -199,10 +198,6 @@ File_class::flush() const ::fflush(m_file); return ::fsync(::fileno(m_file)); #else - return 0; + return ::fflush(m_file);; #endif } - -// -// PRIVATE -// diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 88cb9aad2e4..2b2e0e649a4 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -5083,7 +5083,7 @@ void Dbtc::execLQHKEYREF(Signal* signal) ptrAss(tcConnectptr, tcConnectRecord); TcConnectRecord * const regTcPtr = tcConnectptr.p; if (regTcPtr->tcConnectstate == OS_OPERATING) { - apiConnectptr.i = regTcPtr->apiConnect; + Uint32 save = apiConnectptr.i = regTcPtr->apiConnect; ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); ApiConnectRecord * const regApiPtr = apiConnectptr.p; compare_transid1 = regApiPtr->transid[0] ^ lqhKeyRef->transId1; @@ -5194,7 +5194,7 @@ void Dbtc::execLQHKEYREF(Signal* signal) regApiPtr->lqhkeyreqrec--; // Compensate for extra during read tcKeyRef->connectPtr = indexOp; EXECUTE_DIRECT(DBTC, GSN_TCKEYREF, signal, TcKeyRef::SignalLength); - apiConnectptr.i = regTcPtr->apiConnect; + apiConnectptr.i = save; apiConnectptr.p = regApiPtr; } else { jam(); @@ -5219,6 +5219,8 @@ void Dbtc::execLQHKEYREF(Signal* signal) jam(); sendtckeyconf(signal, 1); regApiPtr->apiConnectstate = CS_CONNECTED; + regApiPtr->m_transaction_nodes.clear(); + setApiConTimer(apiConnectptr.i, 0,__LINE__); } return; } else if (regApiPtr->tckeyrec > 0 || regApiPtr->m_exec_flag) { @@ -11877,17 +11879,6 @@ void Dbtc::execTCKEYREF(Signal* signal) case(IOS_INDEX_ACCESS_WAIT_FOR_TRANSID_AI): case(IOS_INDEX_ACCESS_WAIT_FOR_TCKEYCONF): { jam(); - // If we fail index access for a non-read operation during commit - // we abort transaction - if (commitFlg == 1) { - jam(); - releaseIndexOperation(regApiPtr, indexOp); - apiConnectptr.i = indexOp->connectionIndex; - ptrCheckGuard(apiConnectptr, capiConnectFilesize, apiConnectRecord); - terrorCode = tcKeyRef->errorCode; - abortErrorLab(signal); - break; - } /** * Increase count as it will be decreased below... * (and the code is written to handle failing lookup on "real" table diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 1ab313b0b5f..ebef5510b55 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -1912,7 +1912,7 @@ MgmtSrvr::handleStatus(NodeId nodeId, bool alive, bool nfComplete) m_started_nodes.push_back(nodeId); rep->setEventType(NDB_LE_Connected); } else { - rep->setEventType(NDB_LE_Connected); + rep->setEventType(NDB_LE_Disconnected); if(nfComplete) { DBUG_VOID_RETURN; diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index 14946f72e22..2fe43b8cc21 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -473,6 +473,7 @@ NdbTransaction::executeNoBlobs(ExecType aTypeOfExec, * This timeout situation can occur if NDB crashes. */ ndbout << "This timeout should never occur, execute(..)" << endl; + theError.code = 4012; setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure" DBUG_RETURN(-1); }//if @@ -1965,6 +1966,14 @@ NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf, theGlobalCheckpointId = tGCI; } else if ((tNoComp >= tNoSent) && (theLastExecOpInList->theCommitIndicator == 1)){ + + if (m_abortOption == AO_IgnoreError && theError.code != 0){ + /** + * There's always a TCKEYCONF when using IgnoreError + */ + return -1; + } + /**********************************************************************/ // We sent the transaction with Commit flag set and received a CONF with // no Commit flag set. This is clearly an anomaly. diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index d1eeb3ad9d2..75ec5df60cb 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -951,6 +951,7 @@ Ndb::check_send_timeout() //abort(); #endif a_con->theReleaseOnClose = true; + a_con->theError.code = 4012; a_con->setOperationErrorCodeAbort(4012); a_con->theCommitStatus = NdbTransaction::NeedAbort; a_con->theCompletionStatus = NdbTransaction::CompletedFailure; diff --git a/ndb/test/ndbapi/testBasic.cpp b/ndb/test/ndbapi/testBasic.cpp index fcd4f0ed723..a9487262ea3 100644 --- a/ndb/test/ndbapi/testBasic.cpp +++ b/ndb/test/ndbapi/testBasic.cpp @@ -1033,6 +1033,28 @@ runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int +runBug25090(NDBT_Context* ctx, NDBT_Step* step){ + + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary * dict = pNdb->getDictionary(); + + HugoOperations ops(*ctx->getTab()); + + int loops = ctx->getNumLoops(); + const int rows = ctx->getNumRecords(); + + while (loops--) + { + ops.startTransaction(pNdb); + ops.pkReadRecord(pNdb, 1, 1); + ops.execute_Commit(pNdb, AO_IgnoreError); + sleep(10); + ops.closeTransaction(pNdb); + } + + return NDBT_OK; +} NDBT_TESTSUITE(testBasic); TESTCASE("PkInsert", @@ -1276,6 +1298,10 @@ TESTCASE("Fill", INITIALIZER(runPkRead); FINALIZER(runClearTable2); } +TESTCASE("Bug25090", + "Verify what happens when we fill the db" ){ + STEP(runBug25090); +} NDBT_TESTSUITE_END(testBasic); #if 0 diff --git a/ndb/test/ndbapi/testIndex.cpp b/ndb/test/ndbapi/testIndex.cpp index 68635a52289..78672cd519f 100644 --- a/ndb/test/ndbapi/testIndex.cpp +++ b/ndb/test/ndbapi/testIndex.cpp @@ -1238,7 +1238,64 @@ runBug21384(NDBT_Context* ctx, NDBT_Step* step) return NDBT_OK; } +int +runBug25059(NDBT_Context* ctx, NDBT_Step* step) +{ + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary * dict = pNdb->getDictionary(); + const NdbDictionary::Index * idx = dict->getIndex(pkIdxName, *ctx->getTab()); + HugoOperations ops(*ctx->getTab(), idx); + + int res = NDBT_OK; + int loops = ctx->getNumLoops(); + const int rows = ctx->getNumRecords(); + + while (res == NDBT_OK && loops--) + { + ops.startTransaction(pNdb); + ops.pkReadRecord(pNdb, 10 + rand() % rows, rows); + int tmp; + if (tmp = ops.execute_Commit(pNdb, AO_IgnoreError)) + { + if (tmp == 4012) + res = NDBT_FAILED; + else + if (ops.getTransaction()->getNdbError().code == 4012) + res = NDBT_FAILED; + } + ops.closeTransaction(pNdb); + } + + loops = ctx->getNumLoops(); + while (res == NDBT_OK && loops--) + { + ops.startTransaction(pNdb); + ops.pkUpdateRecord(pNdb, 10 + rand() % rows, rows); + int tmp; + int arg; + switch(rand() % 2){ + case 0: + arg = AbortOnError; + break; + case 1: + arg = AO_IgnoreError; + ndbout_c("ignore error"); + break; + } + if (tmp = ops.execute_Commit(pNdb, (AbortOption)arg)) + { + if (tmp == 4012) + res = NDBT_FAILED; + else + if (ops.getTransaction()->getNdbError().code == 4012) + res = NDBT_FAILED; + } + ops.closeTransaction(pNdb); + } + + return res; +} NDBT_TESTSUITE(testIndex); TESTCASE("CreateAll", @@ -1563,6 +1620,14 @@ TESTCASE("Bug21384", FINALIZER(createPkIndex_Drop); FINALIZER(runClearTable); } +TESTCASE("Bug25059", + "Test that unique indexes and nulls"){ + TC_PROPERTY("LoggedIndexes", (unsigned)0); + INITIALIZER(createPkIndex); + INITIALIZER(runLoadTable); + STEP(runBug25059); + FINALIZER(createPkIndex_Drop); +} NDBT_TESTSUITE_END(testIndex); int main(int argc, const char** argv){ diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index bbfc2f630b9..5fc10f6284b 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -211,6 +211,14 @@ max-time: 500 cmd: testTimeout args: T1 +max-time: 500 +cmd: testBasic +args: -n Bug25090 T1 + +max-time: 500 +cmd: testIndex +args: -n Bug25059 -r 3000 T1 + # SCAN TESTS # max-time: 500 diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index ae23b7ece4c..6508216e3d6 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1433,6 +1433,16 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) /* Connect to foreign database mysql_real_connect() */ mysql= mysql_init(0); + + /* + BUG# 17044 Federated Storage Engine is not UTF8 clean + Add set names to whatever charset the table is at open + of table + */ + /* this sets the csname like 'set names utf8' */ + mysql_options(mysql,MYSQL_SET_CHARSET_NAME, + this->table->s->table_charset->csname); + if (!mysql || !mysql_real_connect(mysql, share->hostname, share->username, @@ -1449,6 +1459,7 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) API silently reconnect. For future versions, we will need more logic to deal with transactions */ + mysql->reconnect= 1; ref_length= (table->s->primary_key != MAX_KEY ? diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6b7355fa176..079501f309b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -874,7 +874,11 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() if (file) { range_end(); - file->extra(HA_EXTRA_NO_KEYREAD); + if (head->key_read) + { + head->key_read= 0; + file->extra(HA_EXTRA_NO_KEYREAD); + } if (free_file) { DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, @@ -1016,8 +1020,12 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) if (reuse_handler) { DBUG_PRINT("info", ("Reusing handler %p", file)); - if (file->extra(HA_EXTRA_KEYREAD) || - file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || + if (!head->no_keyread) + { + head->key_read= 1; + file->extra(HA_EXTRA_KEYREAD); + } + if (file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || init() || reset()) { DBUG_RETURN(1); @@ -1040,9 +1048,12 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) } if (file->external_lock(thd, F_RDLCK)) goto failure; - - if (file->extra(HA_EXTRA_KEYREAD) || - file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || + if (!head->no_keyread) + { + head->key_read= 1; + file->extra(HA_EXTRA_KEYREAD); + } + if (file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || init() || reset()) { file->external_lock(thd, F_UNLCK); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index dd88d81f167..be6707c80a9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1744,8 +1744,6 @@ void kill_delayed_threads(void) delayed_insert *tmp; while ((tmp=it++)) { - /* Ensure that the thread doesn't kill itself while we are looking at it */ - pthread_mutex_lock(&tmp->mutex); tmp->thd.killed= THD::KILL_CONNECTION; if (tmp->thd.mysys_var) { @@ -1764,7 +1762,6 @@ void kill_delayed_threads(void) } pthread_mutex_unlock(&tmp->thd.mysys_var->mutex); } - pthread_mutex_unlock(&tmp->mutex); } VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 73395eae113..007c5edd673 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7038,6 +7038,7 @@ bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; create_info.default_table_charset= thd->variables.collation_database; + create_info.row_type= ROW_TYPE_NOT_USED; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name, &create_info, table_list, fields, keys, 0, (ORDER*)0, @@ -7054,6 +7055,7 @@ bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info) bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; create_info.default_table_charset= thd->variables.collation_database; + create_info.row_type= ROW_TYPE_NOT_USED; alter_info->clear(); alter_info->flags= ALTER_DROP_INDEX; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name, |