From c4021e2d43f7b1f21d69f819955a574d812ea8fa Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 7 May 2010 00:41:37 +0400 Subject: [PATCH 1/2] Bug #53088: mysqldump with -T & --default-character-set set truncates text/blob to 766 chars mysqldump and SELECT ... INTO OUTFILE truncated long BLOB/TEXT values to size of 766 bytes (MAX_FIELD_WIDTH or 255 * 3 + 1). The select_export::send_data method has been modified to reallocate a conversion buffer for long field data. --- mysql-test/r/mysqldump.result | 15 ++++++++++++ mysql-test/r/outfile_loaddata.result | 20 ++++++++++++++++ mysql-test/t/mysqldump.test | 29 ++++++++++++++++++++++++ mysql-test/t/outfile_loaddata.test | 34 ++++++++++++++++++++++++++++ sql/sql_class.cc | 25 ++++++++++++++++++-- 5 files changed, 121 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 8162e1aca05..d26eaac7a93 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4561,5 +4561,20 @@ a b c SET NAMES default; DROP TABLE t1, t2; # +# Bug #53088: mysqldump with -T & --default-character-set set +# truncates text/blob to 766 chars +# +# Also see outfile_loaddata.test +# +CREATE TABLE t1 (a BLOB) CHARSET latin1; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (REPEAT('.', 800)); +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/t1.txt' INTO TABLE t2 CHARACTER SET latin1; +# should be 800 +SELECT LENGTH(a) FROM t2; +LENGTH(a) +800 +DROP TABLE t1, t2; +# # End of 5.1 tests # diff --git a/mysql-test/r/outfile_loaddata.result b/mysql-test/r/outfile_loaddata.result index 453e3adb54c..36a72fd84ce 100644 --- a/mysql-test/r/outfile_loaddata.result +++ b/mysql-test/r/outfile_loaddata.result @@ -239,4 +239,24 @@ a b c 2 NULL NULL SET NAMES default; DROP TABLE t1, t2; +# +# Bug #53088: mysqldump with -T & --default-character-set set +# truncates text/blob to 766 chars +# +# Also see mysqldump.test +# +CREATE TABLE t1 (a BLOB) CHARSET latin1; +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (REPEAT('.', 800)); +SELECT * INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug53088.txt' CHARACTER SET latin1 FROM t1; +# should be greater than 800 +SELECT LENGTH(LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug53088.txt')); +LENGTH(LOAD_FILE('MYSQLTEST_VARDIR/tmp/bug53088.txt')) +801 +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug53088.txt' INTO TABLE t2; +# should be 800 +SELECT LENGTH(a) FROM t2; +LENGTH(a) +800 +DROP TABLE t1, t2; # End of 5.1 tests. diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 07ab9cecd28..0bf9916dcd5 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2131,6 +2131,35 @@ SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a, b, c; SET NAMES default; +DROP TABLE t1, t2; +########################################################################### + +--echo # +--echo # Bug #53088: mysqldump with -T & --default-character-set set +--echo # truncates text/blob to 766 chars +--echo # +--echo # Also see outfile_loaddata.test +--echo # + +CREATE TABLE t1 (a BLOB) CHARSET latin1; +CREATE TABLE t2 LIKE t1; + +let $table= t1; +let $dir= $MYSQLTEST_VARDIR/tmp; +let $file= $dir/$table.txt; +let $length= 800; + +--eval INSERT INTO t1 VALUES (REPEAT('.', $length)) + +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --default-character-set=latin1 --tab=$dir/ test $table +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR + +--eval LOAD DATA INFILE '$file' INTO TABLE t2 CHARACTER SET latin1 +--remove_file $file + +--echo # should be $length +SELECT LENGTH(a) FROM t2; + DROP TABLE t1, t2; ########################################################################### diff --git a/mysql-test/t/outfile_loaddata.test b/mysql-test/t/outfile_loaddata.test index 3f62acbd214..26760f9a1b2 100644 --- a/mysql-test/t/outfile_loaddata.test +++ b/mysql-test/t/outfile_loaddata.test @@ -251,6 +251,40 @@ SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY a, b, c; SET NAMES default; DROP TABLE t1, t2; +########################################################################### + +--echo # +--echo # Bug #53088: mysqldump with -T & --default-character-set set +--echo # truncates text/blob to 766 chars +--echo # +--echo # Also see mysqldump.test +--echo # + +CREATE TABLE t1 (a BLOB) CHARSET latin1; +CREATE TABLE t2 LIKE t1; + +let $file= '$MYSQLTEST_VARDIR/tmp/bug53088.txt'; +let $length= 800; + +--eval INSERT INTO t1 VALUES (REPEAT('.', $length)) + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT * INTO OUTFILE $file CHARACTER SET latin1 FROM t1 + +--echo # should be greater than $length +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT LENGTH(LOAD_FILE($file)) + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE $file INTO TABLE t2 + +--remove_file $MYSQLTEST_VARDIR/tmp/bug53088.txt + +--echo # should be $length +SELECT LENGTH(a) FROM t2; + +DROP TABLE t1, t2; + ########################################################################### --echo # End of 5.1 tests. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2633f03f2d6..b639e590bbc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1998,9 +1998,21 @@ bool select_export::send_data(List &items) const char *from_end_pos; const char *error_pos; uint32 bytes; - bytes= well_formed_copy_nchars(write_cs, cvt_buff, sizeof(cvt_buff), + uint64 estimated_bytes= + ((uint64) res->length() / res->charset()->mbminlen + 1) * + write_cs->mbmaxlen + 1; + set_if_smaller(estimated_bytes, UINT_MAX32); + if (cvt_str.realloc((uint32) estimated_bytes)) + { + my_error(ER_OUTOFMEMORY, MYF(0), (uint32) estimated_bytes); + goto err; + } + + bytes= well_formed_copy_nchars(write_cs, (char *) cvt_str.ptr(), + cvt_str.alloced_length(), res->charset(), res->ptr(), res->length(), - sizeof(cvt_buff), + UINT_MAX32, // copy all input chars, + // i.e. ignore nchars parameter &well_formed_error_pos, &cannot_convert_error_pos, &from_end_pos); @@ -2018,6 +2030,15 @@ bool select_export::send_data(List &items) "string", printable_buff, item->name, row_count); } + else if (from_end_pos < res->ptr() + res->length()) + { + /* + result is longer than UINT_MAX32 and doesn't fit into String + */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED), + item->full_name(), row_count); + } cvt_str.length(bytes); res= &cvt_str; } From 2c83fc6266e377fd85b4e6a1f2b02948c4f3eaad Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 7 May 2010 10:38:42 +0500 Subject: [PATCH 2/2] Bug#53334 Incorrect result for InnoDB in LEFT JOIN with impossible condition The fix actually reverts the change introduced by the patch for bug 51494. The fact is that patches for bugs 52177&48419 fix bugs 51194&50575 as well. --- mysql-test/r/innodb_mysql.result | 30 ++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 30 ++++++++++++++++++++++++++++++ sql/sql_select.cc | 3 +-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 2bf1ef8fbf0..8257b291cf1 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -2378,4 +2378,34 @@ SELECT SECOND(c)-@bug47453 FROM t1 JOIN t2 ON d=a; SECOND(c)-@bug47453 0 DROP TABLE t1, t2; +# +# Bug #53334: wrong result for outer join with impossible ON condition +# (see the same test case for MyISAM in join.test) +# +CREATE TABLE t1 (id INT PRIMARY KEY); +CREATE TABLE t2 (id INT); +INSERT INTO t1 VALUES (75); +INSERT INTO t1 VALUES (79); +INSERT INTO t1 VALUES (78); +INSERT INTO t1 VALUES (77); +REPLACE INTO t1 VALUES (76); +REPLACE INTO t1 VALUES (76); +INSERT INTO t1 VALUES (104); +INSERT INTO t1 VALUES (103); +INSERT INTO t1 VALUES (102); +INSERT INTO t1 VALUES (101); +INSERT INTO t1 VALUES (105); +INSERT INTO t1 VALUES (106); +INSERT INTO t1 VALUES (107); +INSERT INTO t2 VALUES (107),(75),(1000); +SELECT t1.id,t2.id FROM t2 LEFT JOIN t1 ON t1.id>=74 AND t1.id<=0 +WHERE t2.id=75 AND t1.id IS NULL; +id id +NULL 75 +EXPLAIN SELECT t1.id,t2.id FROM t2 LEFT JOIN t1 ON t1.id>=74 AND t1.id<=0 +WHERE t2.id=75 AND t1.id IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY NULL NULL NULL 1 Impossible ON condition +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +DROP TABLE t1,t2; End of 5.1 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 9564d3b41fb..f179f3960a9 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -618,5 +618,35 @@ SELECT SECOND(c)-@bug47453 FROM t1 JOIN t2 ON d=a; DROP TABLE t1, t2; +--echo # +--echo # Bug #53334: wrong result for outer join with impossible ON condition +--echo # (see the same test case for MyISAM in join.test) +--echo # + +CREATE TABLE t1 (id INT PRIMARY KEY); +CREATE TABLE t2 (id INT); + +INSERT INTO t1 VALUES (75); +INSERT INTO t1 VALUES (79); +INSERT INTO t1 VALUES (78); +INSERT INTO t1 VALUES (77); +REPLACE INTO t1 VALUES (76); +REPLACE INTO t1 VALUES (76); +INSERT INTO t1 VALUES (104); +INSERT INTO t1 VALUES (103); +INSERT INTO t1 VALUES (102); +INSERT INTO t1 VALUES (101); +INSERT INTO t1 VALUES (105); +INSERT INTO t1 VALUES (106); +INSERT INTO t1 VALUES (107); + +INSERT INTO t2 VALUES (107),(75),(1000); + +SELECT t1.id,t2.id FROM t2 LEFT JOIN t1 ON t1.id>=74 AND t1.id<=0 + WHERE t2.id=75 AND t1.id IS NULL; +EXPLAIN SELECT t1.id,t2.id FROM t2 LEFT JOIN t1 ON t1.id>=74 AND t1.id<=0 + WHERE t2.id=75 AND t1.id IS NULL; + +DROP TABLE t1,t2; --echo End of 5.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 291432c2bb6..5479c1bdb36 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2967,8 +2967,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; - if (records == 0 && s->table->reginfo.impossible_range && - (s->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) + if (records == 0 && s->table->reginfo.impossible_range) { /* Impossible WHERE or ON expression