From a611fbf171ed7d38b3d69d2a6408b7c751f3342e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 12:22:41 +0200 Subject: [PATCH 01/11] Bug#20719 - Reading dynamic records with write buffer could fail Fixed a possible problem with reading of dynamic records when a write cache is active. The cache must be flushed whenever a part of the file in the write cache is to be read. Added a read optimization to _mi_read_dynamic_record(). No test case. This was a hypothetical but existing problem. myisam/mi_dynrec.c: Bug#20719 - Reading dynamic records with write buffer could fail Fixed a possible problem with reading of dynamic records when a write cache is active. The cache must be flushed whenever a part of the file in the write cache is to be read. This must be done before the read of the header and before the read of the rest block. Renamed the 'flag' and 'skipp_deleted_blocks' variables. Added a read optimization to _mi_read_dynamic_record() that was present in _mi_read_rnd_dynamic_record() already. After _mi_get_block_info() we have some bytes of the record in the header buffer already. No need to read them again. --- myisam/mi_dynrec.c | 157 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 129 insertions(+), 28 deletions(-) diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 0ffab05b6bc..c4865315283 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1095,12 +1095,41 @@ void _my_store_blob_length(byte *pos,uint pack_length,uint length) } - /* Read record from datafile */ - /* Returns 0 if ok, -1 if error */ +/* + Read record from datafile. + + SYNOPSIS + _mi_read_dynamic_record() + info MI_INFO pointer to table. + filepos From where to read the record. + buf Destination for record. + + NOTE + + If a write buffer is active, it needs to be flushed if its contents + intersects with the record to read. We always check if the position + of the first byte of the write buffer is lower than the position + past the last byte to read. In theory this is also true if the write + buffer is completely below the read segment. That is, if there is no + intersection. But this case is unusual. We flush anyway. Only if the + first byte in the write buffer is above the last byte to read, we do + not flush. + + A dynamic record may need several reads. So this check must be done + before every read. Reading a dynamic record starts with reading the + block header. If the record does not fit into the free space of the + header, the block may be longer than the header. In this case a + second read is necessary. These one or two reads repeat for every + part of the record. + + RETURN + 0 OK + -1 Error +*/ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) { - int flag; + int block_of_record; uint b_type,left_length; byte *to; MI_BLOCK_INFO block_info; @@ -1112,17 +1141,16 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) LINT_INIT(to); LINT_INIT(left_length); file=info->dfile; - block_info.next_filepos=filepos; /* for easyer loop */ - flag=block_info.second_read=0; + block_of_record= 0; /* First block of record is numbered as zero. */ + block_info.second_read= 0; do { if (info->opt_flag & WRITE_CACHE_USED && - info->rec_cache.pos_in_file <= block_info.next_filepos && + info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) goto err; info->rec_cache.seek_not_done=1; - if ((b_type=_mi_get_block_info(&block_info,file, - block_info.next_filepos)) + if ((b_type= _mi_get_block_info(&block_info, file, filepos)) & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR)) { @@ -1130,9 +1158,8 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) my_errno=HA_ERR_RECORD_DELETED; goto err; } - if (flag == 0) /* First block */ + if (block_of_record++ == 0) /* First block */ { - flag=1; if (block_info.rec_len > (uint) info->s->base.max_pack_length) goto panic; if (info->s->base.blobs) @@ -1147,11 +1174,35 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) } if (left_length < block_info.data_len || ! block_info.data_len) goto panic; /* Wrong linked record */ - if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos, - MYF(MY_NABP))) - goto panic; - left_length-=block_info.data_len; - to+=block_info.data_len; + /* copy information that is already read */ + { + uint offset= (uint) (block_info.filepos - filepos); + uint prefetch_len= (sizeof(block_info.header) - offset); + filepos+= sizeof(block_info.header); + + if (prefetch_len > block_info.data_len) + prefetch_len= block_info.data_len; + if (prefetch_len) + { + memcpy((byte*) to, block_info.header + offset, prefetch_len); + block_info.data_len-= prefetch_len; + left_length-= prefetch_len; + to+= prefetch_len; + } + } + /* read rest of record from file */ + if (block_info.data_len) + { + if (info->opt_flag & WRITE_CACHE_USED && + info->rec_cache.pos_in_file < filepos + block_info.data_len && + flush_io_cache(&info->rec_cache)) + goto err; + if (my_read(file, (byte*) to, block_info.data_len, MYF(MY_NABP))) + goto panic; + left_length-=block_info.data_len; + to+=block_info.data_len; + } + filepos= block_info.next_filepos; } while (left_length); info->update|= HA_STATE_AKTIV; /* We have a aktive record */ @@ -1308,11 +1359,45 @@ err: } +/* + Read record from datafile. + + SYNOPSIS + _mi_read_rnd_dynamic_record() + info MI_INFO pointer to table. + buf Destination for record. + filepos From where to read the record. + skip_deleted_blocks If to repeat reading until a non-deleted + record is found. + + NOTE + + If a write buffer is active, it needs to be flushed if its contents + intersects with the record to read. We always check if the position + of the first byte of the write buffer is lower than the position + past the last byte to read. In theory this is also true if the write + buffer is completely below the read segment. That is, if there is no + intersection. But this case is unusual. We flush anyway. Only if the + first byte in the write buffer is above the last byte to read, we do + not flush. + + A dynamic record may need several reads. So this check must be done + before every read. Reading a dynamic record starts with reading the + block header. If the record does not fit into the free space of the + header, the block may be longer than the header. In this case a + second read is necessary. These one or two reads repeat for every + part of the record. + + RETURN + 0 OK + != 0 Error +*/ + int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, register my_off_t filepos, - my_bool skipp_deleted_blocks) + my_bool skip_deleted_blocks) { - int flag,info_read,save_errno; + int block_of_record, info_read, save_errno; uint left_len,b_type; byte *to; MI_BLOCK_INFO block_info; @@ -1338,7 +1423,8 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, else info_read=1; /* memory-keyinfoblock is ok */ - flag=block_info.second_read=0; + block_of_record= 0; /* First block of record is numbered as zero. */ + block_info.second_read= 0; left_len=1; do { @@ -1361,15 +1447,15 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, { if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos, sizeof(block_info.header), - (!flag && skipp_deleted_blocks ? READING_NEXT : 0) | - READING_HEADER)) + (!block_of_record && skip_deleted_blocks ? + READING_NEXT : 0) | READING_HEADER)) goto panic; b_type=_mi_get_block_info(&block_info,-1,filepos); } else { if (info->opt_flag & WRITE_CACHE_USED && - info->rec_cache.pos_in_file <= filepos && + info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) DBUG_RETURN(my_errno); info->rec_cache.seek_not_done=1; @@ -1380,7 +1466,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, BLOCK_FATAL_ERROR)) { if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR)) - && skipp_deleted_blocks) + && skip_deleted_blocks) { filepos=block_info.filepos+block_info.block_len; block_info.second_read=0; @@ -1394,7 +1480,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, } goto err; } - if (flag == 0) /* First block */ + if (block_of_record == 0) /* First block */ { if (block_info.rec_len > (uint) share->base.max_pack_length) goto panic; @@ -1427,7 +1513,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, left_len-=tmp_length; to+=tmp_length; filepos+=tmp_length; - } + } } /* read rest of record from file */ if (block_info.data_len) @@ -1436,11 +1522,17 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, { if (_mi_read_cache(&info->rec_cache,(byte*) to,filepos, block_info.data_len, - (!flag && skipp_deleted_blocks) ? READING_NEXT :0)) + (!block_of_record && skip_deleted_blocks) ? + READING_NEXT : 0)) goto panic; } else { + if (info->opt_flag & WRITE_CACHE_USED && + info->rec_cache.pos_in_file < + block_info.filepos + block_info.data_len && + flush_io_cache(&info->rec_cache)) + goto err; /* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */ if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP))) { @@ -1450,10 +1542,14 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, } } } - if (flag++ == 0) + /* + Increment block-of-record counter. If it was the first block, + remember the position behind the block for the next call. + */ + if (block_of_record++ == 0) { - info->nextpos=block_info.filepos+block_info.block_len; - skipp_deleted_blocks=0; + info->nextpos= block_info.filepos + block_info.block_len; + skip_deleted_blocks= 0; } left_len-=block_info.data_len; to+=block_info.data_len; @@ -1485,6 +1581,11 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) if (file >= 0) { + /* + We do not use my_pread() here because we want to have the file + pointer set to the end of the header after this function. + my_pread() may leave the file pointer untouched. + */ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0))); if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) != sizeof(info->header)) From 2347325117ccb0b6b22c8d41a968aa2fd8c17bca Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 17:27:53 +0500 Subject: [PATCH 02/11] Bug#19741 segfault with cp1250 charset + like + primary key + 64bit os LIKE craashed with a pattern having letters in the range 128..255 (e.g. A WITH ACUTE or C WITH CARON) because of wrong cast from signed char to unsigned int. mysql-test/r/ctype_cp1250_ch.result: Adding test case mysql-test/t/ctype_cp1250_ch.test: Adding test case strings/ctype-win1250ch.c: Fixing wrong cast from "signed char" -> "uint" to "signed char" -> "unsigned char" -> uint, to properly handle bytes 128..255. --- mysql-test/r/ctype_cp1250_ch.result | 8 ++++++++ mysql-test/t/ctype_cp1250_ch.test | 10 ++++++++++ strings/ctype-win1250ch.c | 4 ++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ctype_cp1250_ch.result b/mysql-test/r/ctype_cp1250_ch.result index 533bfb8cb53..b55849e4e12 100644 --- a/mysql-test/r/ctype_cp1250_ch.result +++ b/mysql-test/r/ctype_cp1250_ch.result @@ -42,3 +42,11 @@ id str 6 aaaaaa 7 aaaaaaa drop table t1; +set names cp1250; +create table t1 (a varchar(15) collate cp1250_czech_cs NOT NULL, primary key(a)); +insert into t1 values("abcdefghá"); +insert into t1 values("ááèè"); +select a from t1 where a like "abcdefghá"; +a +abcdefghá +drop table t1; diff --git a/mysql-test/t/ctype_cp1250_ch.test b/mysql-test/t/ctype_cp1250_ch.test index 2d1e5f0bf9d..65550e0c193 100644 --- a/mysql-test/t/ctype_cp1250_ch.test +++ b/mysql-test/t/ctype_cp1250_ch.test @@ -44,4 +44,14 @@ INSERT INTO t1 VALUES (NULL, 'aaaaaaa'); select * from t1 where str like 'aa%'; drop table t1; +# +# Bug#19741 segfault with cp1250 charset + like + primary key + 64bit os +# +set names cp1250; +create table t1 (a varchar(15) collate cp1250_czech_cs NOT NULL, primary key(a)); +insert into t1 values("abcdefghá"); +insert into t1 values("ááèè"); +select a from t1 where a like "abcdefghá"; +drop table t1; + # End of 4.1 tests diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index e936ef1d423..b03bbbc155c 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -634,11 +634,11 @@ my_like_range_win1250ch(CHARSET_INFO *cs __attribute__((unused)), ptr++; /* Skip escape */ else if (*ptr == w_one || *ptr == w_many) /* '_' or '%' in SQL */ break; - *min_str = like_range_prefix_min_win1250ch[(uint)(*ptr)]; + *min_str = like_range_prefix_min_win1250ch[(uint) (uchar) (*ptr)]; if (*min_str != min_sort_char) only_min_found= 0; min_str++; - *max_str++ = like_range_prefix_max_win1250ch[(uint)(*ptr)]; + *max_str++ = like_range_prefix_max_win1250ch[(uint) (uchar) (*ptr)]; } *min_length = (uint) (min_str - min_org); From fe4d656d552c864affbffda7d330a120bcac87a5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 18:38:09 -0400 Subject: [PATCH 03/11] BUG #15133 "unique index with nullable value not accepted in federated table" Added HA_NULL_IN_KEY to table flags to allow for nullable unique indexes and added test to verify ha_federated.h: BUG #15133 "unique index with nullable value not accepted in federated table" added HA_NULL_IN_KEY to table flags to allow for nullable unique indexes federated.test: BUG #15133 "unique index with nullable value not accepted in federated table" New test to show that nullable unique indexes work federated.result: BUG #15133 "unique index with nullable value not accepted in federated table" New results for new test sql/ha_federated.h: BUG #15133 "unique index with nullable value not accepted in federated table" added HA_NULL_IN_KEY to table flags to allow for nullable unique indexes mysql-test/t/federated.test: BUG #15133 "unique index with nullable value not accepted in federated table" New test to show that nullable unique indexes work mysql-test/r/federated.result: BUG #15133 "unique index with nullable value not accepted in federated table" New results for new test --- mysql-test/r/federated.result | 27 +++++++++++++++++++++ mysql-test/t/federated.test | 45 +++++++++++++++++++++++++++++++++++ sql/ha_federated.h | 4 +++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 5d17afd8cfc..5e827a34e87 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -1784,6 +1784,33 @@ length(a) 5000 drop table t1; drop table t1; +DROP TABLE IF EXISTS federated.test; +CREATE TABLE federated.test ( +`i` int(11) NOT NULL, +`j` int(11) NOT NULL, +`c` varchar(30) default NULL, +PRIMARY KEY (`i`,`j`), +UNIQUE KEY `i` (`i`,`c`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS federated.test1; +DROP TABLE IF EXISTS federated.test2; +create table federated.test1 ( +i int not null, +j int not null, +c varchar(30), +primary key (i,j), +unique key (i, c)) +engine = federated +connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/test'; +create table federated.test2 ( +i int default null, +j int not null, +c varchar(30), +key (i)) +engine = federated +connection='mysql://root@127.0.0.1:SLAVE_PORT/federated/test'; +drop table federated.test1, federated.test2; +drop table federated.test; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index 38beab605fd..c2218b3451b 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -1499,4 +1499,49 @@ drop table t1; connection master; drop table t1; +# +# BUG #15133: unique index with nullable value not accepted in federated table +# + +connection slave; +--disable_warnings +DROP TABLE IF EXISTS federated.test; +CREATE TABLE federated.test ( + `i` int(11) NOT NULL, + `j` int(11) NOT NULL, + `c` varchar(30) default NULL, + PRIMARY KEY (`i`,`j`), + UNIQUE KEY `i` (`i`,`c`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +--enable_warnings + +connection master; +--disable_warnings +DROP TABLE IF EXISTS federated.test1; +DROP TABLE IF EXISTS federated.test2; +--enable_warnings + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.test1 ( + i int not null, + j int not null, + c varchar(30), + primary key (i,j), + unique key (i, c)) +engine = federated +connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/test'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.test2 ( + i int default null, + j int not null, + c varchar(30), + key (i)) +engine = federated +connection='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/test'; +drop table federated.test1, federated.test2; + +connection slave; +drop table federated.test; + source include/federated_cleanup.inc; diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 85474d142a3..61f5af686a3 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -196,7 +196,9 @@ public: /* fix server to be able to get remote server table flags */ return (HA_NOT_EXACT_COUNT | HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | HA_REC_NOT_IN_SEQ | - HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS| HA_NO_PREFIX_CHAR_KEYS); + HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS| HA_NO_PREFIX_CHAR_KEYS | + HA_NULL_IN_KEY + ); } /* This is a bitmap of flags that says how the storage engine From 721b1d7fc69a32fab4c055691e8ee1fb93e0abda Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Jul 2006 21:58:50 +0200 Subject: [PATCH 04/11] Bug#20719 - Reading dynamic records with write buffer could fail After merge fix --- myisam/mi_dynrec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 51f2ff349f8..4dec3055fa1 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1141,6 +1141,9 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) block_info.second_read= 0; do { + /* A corrupted table can have wrong pointers. (Bug# 19835) */ + if (filepos == HA_OFFSET_ERROR) + goto panic; if (info->opt_flag & WRITE_CACHE_USED && info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) From 9493d46476230837d7bc27d5c938105d471bb5a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 30 Jul 2006 06:19:30 +0200 Subject: [PATCH 05/11] Bug#20719 - Reading dynamic records with write buffer could fail After merge fix --- myisam/mi_dynrec.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index f834cc5a724..ef5ab73f1a9 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1187,9 +1187,6 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) goto err; - /* A corrupted table can have wrong pointers. (Bug# 19835) */ - if (block_info.next_filepos == HA_OFFSET_ERROR) - goto panic; info->rec_cache.seek_not_done=1; if ((b_type= _mi_get_block_info(&block_info, file, filepos)) & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | From 3558db995c7db4778db087b7306caa733371fb77 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Aug 2006 09:36:34 -0700 Subject: [PATCH 06/11] Bug#15669 "Test case 'csv' produces incorrect result on OpenBSD" mmapped pages were not being invalidated when writes occurred to the file vi a fd i/o operation. Force explicit invalidation and not rely on implicit invalidation. sql/examples/ha_tina.cc: Bug#15669 Make sure to invalidate in memory pages when the file has been altered by fd i/o. This is important to some operating systems, such as OpenBSD. --- sql/examples/ha_tina.cc | 64 +++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 8ae82f97d0b..524ce5eb693 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -101,13 +101,34 @@ static byte* tina_get_key(TINA_SHARE *share,uint *length, return (byte*) share->table_name; } + +int free_mmap(TINA_SHARE *share) +{ + DBUG_ENTER("ha_tina::free_mmap"); + if (share->mapped_file) + { + /* + Invalidate the mapped in pages. Some operating systems (eg OpenBSD) + would reuse already cached pages even if the file has been altered + using fd based I/O. This may be optimized by perhaps only invalidating + the last page but optimization of deprecated code is not important. + */ + msync(share->mapped_file, 0, MS_INVALIDATE); + if (munmap(share->mapped_file, share->file_stat.st_size)) + DBUG_RETURN(1); + } + share->mapped_file= NULL; + DBUG_RETURN(0); +} + /* Reloads the mmap file. */ int get_mmap(TINA_SHARE *share, int write) { DBUG_ENTER("ha_tina::get_mmap"); - if (share->mapped_file && munmap(share->mapped_file, share->file_stat.st_size)) + + if (free_mmap(share)) DBUG_RETURN(1); if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1) @@ -230,8 +251,7 @@ static int free_share(TINA_SHARE *share) int result_code= 0; if (!--share->use_count){ /* Drop the mapped file */ - if (share->mapped_file) - munmap(share->mapped_file, share->file_stat.st_size); + free_mmap(share); result_code= my_close(share->data_file,MYF(0)); hash_delete(&tina_open_tables, (byte*) share); thr_lock_delete(&share->lock); @@ -493,6 +513,13 @@ int ha_tina::write_row(byte * buf) size= encode_quote(buf); + /* + we are going to alter the file so we must invalidate the in memory pages + otherwise we risk a race between the in memory pages and the disk pages. + */ + if (free_mmap(share)) + DBUG_RETURN(-1); + if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) DBUG_RETURN(-1); @@ -534,8 +561,26 @@ int ha_tina::update_row(const byte * old_data, byte * new_data) if (chain_append()) DBUG_RETURN(-1); + /* + we are going to alter the file so we must invalidate the in memory pages + otherwise we risk a race between the in memory pages and the disk pages. + */ + if (free_mmap(share)) + DBUG_RETURN(-1); + if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP))) DBUG_RETURN(-1); + + /* + Ok, this is means that we will be doing potentially bad things + during a bulk update on some OS'es. Ideally, we should extend the length + of the file, redo the mmap and then write all the updated rows. Upon + finishing the bulk update, truncate the file length to the final length. + Since this code is all being deprecated, not point now to optimize. + */ + if (get_mmap(share, 0) > 0) + DBUG_RETURN(-1); + DBUG_RETURN(0); } @@ -812,15 +857,14 @@ int ha_tina::rnd_end() length= length - (size_t)(ptr->end - ptr->begin); } + /* Invalidate all cached mmap pages */ + if (free_mmap(share)) + DBUG_RETURN(-1); + /* Truncate the file to the new size */ if (my_chsize(share->data_file, length, 0, MYF(MY_WME))) DBUG_RETURN(-1); - if (munmap(share->mapped_file, length)) - DBUG_RETURN(-1); - - /* We set it to null so that get_mmap() won't try to unmap it */ - share->mapped_file= NULL; if (get_mmap(share, 0) > 0) DBUG_RETURN(-1); } @@ -838,6 +882,10 @@ int ha_tina::delete_all_rows() if (!records_is_known) return (my_errno=HA_ERR_WRONG_COMMAND); + /* Invalidate all cached mmap pages */ + if (free_mmap(share)) + DBUG_RETURN(-1); + int rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME)); if (get_mmap(share, 0) > 0) From a1bd0bd1182d9acb6a8484e79259c2f80db042fd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Aug 2006 17:15:50 +0500 Subject: [PATCH 07/11] BUG#14770 - LOAD DATA INFILE doesn't respect default values for columns Fixed confusing warning. Quoting INSERT section of the manual: ---- Inserting NULL into a column that has been declared NOT NULL. For multiple-row INSERT statements or INSERT INTO ... SELECT statements, the column is set to the implicit default value for the column data type. This is 0 for numeric types, the empty string ('') for string types, and the "zero" value for date and time types. INSERT INTO ... SELECT statements are handled the same way as multiple-row inserts because the server does not examine the result set from the SELECT to see whether it returns a single row. (For a single-row INSERT, no warning occurs when NULL is inserted into a NOT NULL column. Instead, the statement fails with an error.) ---- This is also true for LOAD DATA INFILE. For INSERT user can specify DEFAULT keyword as a value to set column default. There is no similiar feature available for LOAD DATA INFILE. mysql-test/r/auto_increment.result: Fixed confusing warning. mysql-test/r/create.result: Fixed confusing warning. mysql-test/r/insert.result: Fixed confusing warning. mysql-test/r/insert_select.result: Fixed confusing warning. mysql-test/r/key.result: Fixed confusing warning. mysql-test/r/null.result: Fixed confusing warning. mysql-test/r/null_key.result: Fixed confusing warning. mysql-test/r/ps_2myisam.result: Fixed confusing warning. mysql-test/r/ps_3innodb.result: Fixed confusing warning. mysql-test/r/ps_4heap.result: Fixed confusing warning. mysql-test/r/ps_5merge.result: Fixed confusing warning. mysql-test/r/ps_6bdb.result: Fixed confusing warning. mysql-test/r/strict.result: Fixed confusing warning. mysql-test/r/view.result: Fixed confusing warning. mysql-test/r/warnings.result: Fixed confusing warning. sql/share/errmsg.txt: Fixed confusing warning. --- mysql-test/r/auto_increment.result | 4 ++-- mysql-test/r/create.result | 2 +- mysql-test/r/insert.result | 2 +- mysql-test/r/insert_select.result | 4 ++-- mysql-test/r/key.result | 4 ++-- mysql-test/r/null.result | 18 +++++++++--------- mysql-test/r/null_key.result | 2 +- mysql-test/r/ps_2myisam.result | 2 +- mysql-test/r/ps_3innodb.result | 2 +- mysql-test/r/ps_4heap.result | 2 +- mysql-test/r/ps_5merge.result | 4 ++-- mysql-test/r/ps_6bdb.result | 2 +- mysql-test/r/strict.result | 18 +++++++++--------- mysql-test/r/view.result | 2 +- mysql-test/r/warnings.result | 8 ++++---- sql/share/errmsg.txt | 4 ++-- 16 files changed, 40 insertions(+), 40 deletions(-) diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index afbff905699..d0058118e4c 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -232,7 +232,7 @@ a b delete from t1 where a=0; update t1 set a=NULL where b=6; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 4 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 4 update t1 set a=300 where b=7; SET SQL_MODE=''; insert into t1(a,b)values(NULL,8); @@ -274,7 +274,7 @@ a b delete from t1 where a=0; update t1 set a=NULL where b=13; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 9 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 9 update t1 set a=500 where b=14; select * from t1 order by b; a b diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index c5b77ea4925..f3dfec3d469 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -13,7 +13,7 @@ Warnings: Note 1050 Table 't1' already exists insert into t1 values (""),(null); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'b' at row 2 select * from t1; b diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 82fad8e912c..80723d68b5a 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -63,7 +63,7 @@ insert into t1 values(NULL); ERROR 23000: Column 'id' cannot be null insert into t1 values (1), (NULL), (2); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'id' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'id' at row 2 select * from t1; id 1 diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 49d9c3594db..34e3f0ca2e8 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -606,8 +606,8 @@ NULL 2 100 create table t2(No int not null, Field int not null, Count int not null); insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'No' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'No' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'No' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'No' at row 2 select * from t2; No Field Count 0 1 100 diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 0174ea45935..eea884e4294 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -159,8 +159,8 @@ CREATE TABLE t1 (c CHAR(10) NOT NULL,i INT NOT NULL AUTO_INCREMENT, UNIQUE (c,i)); INSERT INTO t1 (c) VALUES (NULL),(NULL); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'c' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'c' at row 2 SELECT * FROM t1; c i 1 diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 18eb10f0673..daedfa50b80 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -97,39 +97,39 @@ Warnings: Warning 1265 Data truncated for column 'd' at row 1 UPDATE t1 SET d=NULL; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'd' at row 1 INSERT INTO t1 (a) values (null); ERROR 23000: Column 'a' cannot be null INSERT INTO t1 (a) values (1/null); ERROR 23000: Column 'a' cannot be null INSERT INTO t1 (a) values (null),(null); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 2 INSERT INTO t1 (b) values (null); ERROR 23000: Column 'b' cannot be null INSERT INTO t1 (b) values (1/null); ERROR 23000: Column 'b' cannot be null INSERT INTO t1 (b) values (null),(null); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'b' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'b' at row 2 INSERT INTO t1 (c) values (null); ERROR 23000: Column 'c' cannot be null INSERT INTO t1 (c) values (1/null); ERROR 23000: Column 'c' cannot be null INSERT INTO t1 (c) values (null),(null); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'c' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'c' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'c' at row 2 INSERT INTO t1 (d) values (null); ERROR 23000: Column 'd' cannot be null INSERT INTO t1 (d) values (1/null); ERROR 23000: Column 'd' cannot be null INSERT INTO t1 (d) values (null),(null); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'd' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'd' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'd' at row 2 select * from t1; a b c d 0 0000-00-00 00:00:00 0 diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 7f746a3dbd8..6eb3cf312a0 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -342,7 +342,7 @@ index (id2) ); insert into t1 values(null,null),(1,1); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'id2' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'id2' at row 1 select * from t1; id id2 NULL 0 diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 207d9ea7475..4f2ba36fd3f 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1304,7 +1304,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 13aa549949c..0b41e1f161a 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1287,7 +1287,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index a08dae945bd..a0b797f2e68 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1288,7 +1288,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 6682b085097..4164e244457 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1330,7 +1330,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two @@ -4344,7 +4344,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index dc3b984949d..858cce7d963 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1287,7 +1287,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index d0cf11d0511..b027709c435 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -989,16 +989,16 @@ ERROR 23000: Column 'col2' cannot be null INSERT INTO t1 VALUES (103,'',NULL); ERROR 23000: Column 'col3' cannot be null UPDATE t1 SET col1=NULL WHERE col1 =100; -ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1 +ERROR 22004: Column was set to data type implicit default; NULL supplied for NOT NULL column 'col1' at row 1 UPDATE t1 SET col2 =NULL WHERE col2 ='hello'; -ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1 +ERROR 22004: Column was set to data type implicit default; NULL supplied for NOT NULL column 'col2' at row 1 UPDATE t1 SET col2 =NULL where col3 IS NOT NULL; -ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1 +ERROR 22004: Column was set to data type implicit default; NULL supplied for NOT NULL column 'col2' at row 1 INSERT IGNORE INTO t1 values (NULL,NULL,NULL); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col3' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'col1' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'col2' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'col3' at row 1 SELECT * FROM t1; col1 col2 col3 100 hello 2004-08-20 @@ -1023,11 +1023,11 @@ ERROR HY000: Field 'col2' doesn't have a default value INSERT INTO t1 (col1) SELECT 1; ERROR HY000: Field 'col2' doesn't have a default value INSERT INTO t1 SELECT 1,NULL; -ERROR 22004: Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1 +ERROR 22004: Column was set to data type implicit default; NULL supplied for NOT NULL column 'col2' at row 1 INSERT IGNORE INTO t1 values (NULL,NULL); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col1' at row 1 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'col2' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'col1' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'col2' at row 1 INSERT IGNORE INTO t1 (col1) values (3); Warnings: Warning 1364 Field 'col2' doesn't have a default value diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 72cffb9531c..b532aa8ef8a 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1495,7 +1495,7 @@ insert into v3(b) values (10); insert into v3(a) select a from t2; insert into v3(b) select b from t2; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 2 insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a); select * from t1; a b diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index f9006ebca37..2b1993bdd90 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -72,7 +72,7 @@ drop table t1; create table t1(a tinyint, b int not null, c date, d char(5)); load data infile '../std_data_ln/warnings_loaddata.dat' into table t1 fields terminated by ','; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'b' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'b' at row 2 Warning 1265 Data truncated for column 'd' at row 3 Warning 1265 Data truncated for column 'c' at row 4 Warning 1261 Row 5 doesn't contain data for all columns @@ -86,7 +86,7 @@ drop table t1; create table t1(a tinyint NOT NULL, b tinyint unsigned, c char(5)); insert into t1 values(NULL,100,'mysql'),(10,-1,'mysql ab'),(500,256,'open source'),(20,NULL,'test'); Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'b' at row 2 Warning 1265 Data truncated for column 'c' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 @@ -99,7 +99,7 @@ Warning 1265 Data truncated for column 'c' at row 2 alter table t1 add d char(2); update t1 set a=NULL where a=10; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 2 update t1 set c='mysql ab' where c='test'; Warnings: Warning 1265 Data truncated for column 'c' at row 4 @@ -115,7 +115,7 @@ Warnings: Warning 1265 Data truncated for column 'b' at row 1 Warning 1265 Data truncated for column 'b' at row 2 Warning 1265 Data truncated for column 'b' at row 3 -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 4 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 4 Warning 1265 Data truncated for column 'b' at row 4 insert into t2(b) values('mysqlab'); Warnings: diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9b20c37ece2..4b2408be6d0 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4893,8 +4893,8 @@ ER_WARN_TOO_MANY_RECORDS 01000 por "Conta de registro é maior que a conta de coluna na linha %ld" spa "Línea %ld fué truncada; La misma contine mas datos que las que existen en las columnas de entrada" ER_WARN_NULL_TO_NOTNULL 22004 - eng "Column set to default value; NULL supplied to NOT NULL column '%s' at row %ld" - ger "Feld auf Vorgabewert gesetzt, da NULL für NOT-NULL-Feld '%s' in Zeile %ld angegeben" + eng "Column was set to data type implicit default; NULL supplied for NOT NULL column '%s' at row %ld" + ger "Feld auf Datentyp-spezifischen Vorgabewert gesetzt; da NULL für NOT-NULL-Feld '%s' in Zeile %ld angegeben" por "Dado truncado, NULL fornecido para NOT NULL coluna '%s' na linha %ld" spa "Datos truncado, NULL suministrado para NOT NULL columna '%s' en la línea %ld" ER_WARN_DATA_OUT_OF_RANGE 22003 From f3ea109f9bbe15becddb14238b26ae683dfbcee6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Aug 2006 19:35:02 +0500 Subject: [PATCH 08/11] After merge fix. --- mysql-test/r/ps_7ndb.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 000a20da655..6a014319097 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1287,7 +1287,7 @@ set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; Warnings: -Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 1 +Warning 1263 Column was set to data type implicit default; NULL supplied for NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b 0 two From afa49a5930492ecd5e2b27dd7ba97467a3b3bc82 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Aug 2006 17:41:35 -0700 Subject: [PATCH 09/11] autopush test - sorry for the commit messages, ignore --- sql/ha_federated.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 2267c2b5d79..7919519cdce 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -332,6 +332,7 @@ */ + #include "mysql_priv.h" #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation From ba8be73946c35852cf296c2d30bbf2a0fe06f87f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Aug 2006 03:29:17 -0700 Subject: [PATCH 10/11] Fix for bug#20648 We introduce a new field method for knowing "real size", and we now in archive null unused bits of a row to null before writing. sql/field.cc: data_length for field needs to be calculated directly. sql/field.h: The new method data_length() returns the "real" length of the field. sql/ha_archive.cc: Before a write_row() archive nulls space beyond the size of the row in varchars to make sure that compression only sees NULL. --- sql/field.cc | 5 +++++ sql/field.h | 6 ++++++ sql/ha_archive.cc | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/sql/field.cc b/sql/field.cc index 2c484bb0979..8395b8c6145 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6412,6 +6412,11 @@ void Field_varstring::sql_type(String &res) const } +uint Field_varstring::data_length(const char *from) +{ + return length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); +} + /* Functions to create a packed row. Here the number of length bytes are depending on the given max_length diff --git a/sql/field.h b/sql/field.h index 3306c4123db..2ad564fc753 100644 --- a/sql/field.h +++ b/sql/field.h @@ -144,6 +144,11 @@ public: table, which is located on disk). */ virtual uint32 pack_length_in_rec() const { return pack_length(); } + + /* + data_length() return the "real size" of the data in memory. + */ + virtual uint32 data_length(const char *from) { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } virtual void reset(void) { bzero(ptr,pack_length()); } virtual void reset_fields() {} @@ -1102,6 +1107,7 @@ public: int key_cmp(const byte *str, uint length); uint packed_col_length(const char *to, uint length); uint max_packed_col_length(uint max_length); + uint data_length(const char *from); uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } bool has_charset(void) const diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 3885defb4d5..0fb0bc9f791 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -710,6 +710,28 @@ int ha_archive::write_row(byte *buf) if (init_archive_writer()) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + /* + Varchar structures are constant in size but are not cleaned up request + to request. The following sets all unused space to null to improve + compression. + */ + for (Field **field=table->field ; *field ; field++) + { + DBUG_PRINT("archive",("Pack is %d\n", (*field)->pack_length())); + DBUG_PRINT("archive",("MyPack is %d\n", (*field)->data_length((char*) buf + (*field)->offset()))); + if ((*field)->real_type() == MYSQL_TYPE_VARCHAR) + { + uint actual_length= (*field)->data_length((char*) buf + (*field)->offset()); + uint offset= (*field)->offset() + actual_length + + (actual_length > 255 ? 2 : 1); + DBUG_PRINT("archive",("Offset is %d -> %d\n", actual_length, offset)); + /* + if ((*field)->pack_length() + (*field)->offset() != offset) + bzero(buf + offset, (size_t)((*field)->pack_length() + (actual_length > 255 ? 2 : 1) - (*field)->data_length)); + */ + } + } + share->rows_recorded++; rc= real_write_row(buf, share->archive_write); pthread_mutex_unlock(&share->mutex); From 492e7b081168f1922ef6409ebba77dbf30638185 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Aug 2006 19:18:33 +0400 Subject: [PATCH 11/11] Fix a test case (proper clean up). mysql-test/r/mysqldump.result: Update results. mysql-test/t/mysqldump.test: Fix a bug in the test case that left user mysqltest_1@localhost around (this broke furhter tests). --- mysql-test/r/mysqldump.result | 4 ++-- mysql-test/t/mysqldump.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 4c684be0a3c..6669b33e1bb 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2876,7 +2876,7 @@ drop view v1; drop table t1; drop database mysqldump_dbb; use test; -create user mysqltest_1; +create user mysqltest_1@localhost; create table t1(a int, b varchar(34)); reset master; mysqldump: Couldn't execute 'FLUSH TABLES': Access denied; you need the RELOAD privilege for this operation (1227) @@ -2891,4 +2891,4 @@ CREATE TABLE `t1` ( `b` varchar(34) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; drop table t1; -drop user mysqltest_1; +drop user mysqltest_1@localhost; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4cdfabd4484..848c5360db7 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1273,7 +1273,7 @@ drop database mysqldump_dbb; use test; # Create user without sufficient privs to perform the requested operation -create user mysqltest_1; +create user mysqltest_1@localhost; create table t1(a int, b varchar(34)); # To get consistent output, reset the master, starts over from first log @@ -1308,4 +1308,4 @@ grant REPLICATION CLIENT on *.* to mysqltest_1@localhost; # Clean up drop table t1; -drop user mysqltest_1; +drop user mysqltest_1@localhost;