diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index bc0389980b9..ef5ab73f1a9 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -1130,12 +1130,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; @@ -1147,20 +1176,19 @@ 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 { + /* 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 <= block_info.next_filepos && + 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, - 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)) { @@ -1168,9 +1196,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) @@ -1185,11 +1212,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 */ @@ -1346,11 +1397,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 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; @@ -1376,7 +1461,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 { @@ -1399,15 +1485,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 && skip_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; @@ -1432,7 +1518,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; @@ -1465,7 +1551,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) @@ -1474,11 +1560,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 && skip_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))) { @@ -1488,10 +1580,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; - skip_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; @@ -1523,6 +1619,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)) 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 ed83dfb4b49..3f8083a0e20 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/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/r/federated.result b/mysql-test/r/federated.result index 454790f2df6..2b44fc8bd7e 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -1788,6 +1788,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/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 3e2721fc09a..89ac863b8d2 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/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/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 aa355067d1f..205c084b71f 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 ea7ed9371e8..2e7c4785542 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 fe4de89d6c7..8a0da364598 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 bee7b2400b8..1c6e11f203c 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 d352ec9f9e2..3546b05870a 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/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 8ce4c624fbc..b1986ca62dc 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 diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 08a33734910..e144eed92f5 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -997,16 +997,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 @@ -1031,11 +1031,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 534065a33b6..e7e953e28d9 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 59be512d5a6..283a0661721 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/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/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/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; 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) 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); 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 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 diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 8a5cb3439f7..e90f54608e1 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 diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index 0bc465f16ea..39948964a42 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -636,11 +636,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)]; } if (cs->state & MY_CS_BINSORT)