summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--myisam/mi_check.c90
-rw-r--r--myisam/mi_dynrec.c8
-rw-r--r--myisam/mi_packrec.c366
-rw-r--r--myisam/mi_range.c1
-rw-r--r--myisam/mi_test1.c2
-rw-r--r--myisam/mi_write.c1
-rw-r--r--myisam/rt_split.c4
-rw-r--r--mysql-test/r/alter_table.result15
-rw-r--r--mysql-test/r/federated.result28
-rw-r--r--mysql-test/r/index_merge.result2
-rw-r--r--mysql-test/r/index_merge_ror.result11
-rw-r--r--mysql-test/r/ndb_index_unique.result15
-rw-r--r--mysql-test/t/alter_table.test11
-rw-r--r--mysql-test/t/federated.test32
-rw-r--r--mysql-test/t/index_merge_ror.test15
-rw-r--r--mysql-test/t/ndb_index_unique.test8
-rw-r--r--ndb/include/logger/FileLogHandler.hpp2
-rw-r--r--ndb/include/util/File.hpp4
-rw-r--r--ndb/include/util/Vector.hpp2
-rw-r--r--ndb/src/common/logger/FileLogHandler.cpp2
-rw-r--r--ndb/src/common/util/File.cpp25
-rw-r--r--ndb/src/kernel/blocks/dbtc/DbtcMain.cpp17
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp2
-rw-r--r--ndb/src/ndbapi/NdbTransaction.cpp9
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp1
-rw-r--r--ndb/test/ndbapi/testBasic.cpp26
-rw-r--r--ndb/test/ndbapi/testIndex.cpp65
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt8
-rw-r--r--sql/ha_federated.cc11
-rw-r--r--sql/opt_range.cc23
-rw-r--r--sql/sql_insert.cc3
-rw-r--r--sql/sql_parse.cc2
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,