From 7063bd4d2bfe4688db60b28a15843406299a58f0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Dec 2005 16:37:58 +0400 Subject: [PATCH 01/16] Bug#15377 Valid multibyte sequences are truncated on INSERT ctype-euc_kr.c: ctype-gb2312.c: Adding specific well_formed_length functions for gb2312 and euckr, to allow storing characters which are correct according to the character set specifications but just don't have Unicode mapping. Previously only those which have Unicode mapping could be stored, while unassigned characters lead to data truncation. Many files: new file strings/ctype-gb2312.c: Bug#15377 Valid multibyte sequences are truncated on INSERT Adding specific well_formed_length functions for gb2312 and euckr, to allow storing characters which are correct according to the character set. Previously only those which have Unicode mapping could be stored. strings/ctype-euc_kr.c: Adding specific well_formed_length functions for gb2312 and euckr, to allow storing characters which are correct according to the character set. Previously only those which have Unicode mapping could be stored. --- mysql-test/include/have_euckr.inc | 4 + mysql-test/include/have_gb2312.inc | 4 + mysql-test/r/ctype_euckr.result | 167 +++++++++++++++++++++++++++++ mysql-test/r/ctype_gb2312.result | 167 +++++++++++++++++++++++++++++ mysql-test/r/have_euckr.require | 2 + mysql-test/r/have_gb2312.require | 2 + mysql-test/t/ctype_euckr.test | 33 ++++++ mysql-test/t/ctype_gb2312.test | 33 ++++++ strings/ctype-euc_kr.c | 37 ++++++- strings/ctype-gb2312.c | 37 ++++++- 10 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/have_euckr.inc create mode 100644 mysql-test/include/have_gb2312.inc create mode 100644 mysql-test/r/ctype_euckr.result create mode 100644 mysql-test/r/ctype_gb2312.result create mode 100644 mysql-test/r/have_euckr.require create mode 100644 mysql-test/r/have_gb2312.require create mode 100644 mysql-test/t/ctype_euckr.test create mode 100644 mysql-test/t/ctype_gb2312.test diff --git a/mysql-test/include/have_euckr.inc b/mysql-test/include/have_euckr.inc new file mode 100644 index 00000000000..af794aafc04 --- /dev/null +++ b/mysql-test/include/have_euckr.inc @@ -0,0 +1,4 @@ +-- require r/have_euckr.require +disable_query_log; +show collation like "euckr_korean_ci"; +enable_query_log; diff --git a/mysql-test/include/have_gb2312.inc b/mysql-test/include/have_gb2312.inc new file mode 100644 index 00000000000..4328bc67639 --- /dev/null +++ b/mysql-test/include/have_gb2312.inc @@ -0,0 +1,4 @@ +-- require r/have_gb2312.require +disable_query_log; +show collation like "gb2312_chinese_ci"; +enable_query_log; diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result new file mode 100644 index 00000000000..6017bc07763 --- /dev/null +++ b/mysql-test/r/ctype_euckr.result @@ -0,0 +1,167 @@ +drop table if exists t1; +SET @test_character_set= 'euckr'; +SET @test_collation= 'euckr_korean_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) euckr_korean_ci YES MUL NULL +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) euckr_korean_ci YES MUL NULL +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; +SET NAMES euckr; +SET collation_connection='euckr_korean_ci'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +euckr_korean_ci 6109 +euckr_korean_ci 61 +euckr_korean_ci 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +euckr_korean_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +euckr_korean_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET collation_connection='euckr_bin'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +euckr_bin 6109 +euckr_bin 61 +euckr_bin 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +euckr_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +euckr_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET NAMES euckr; +CREATE TABLE t1 (a text) character set euckr; +INSERT INTO t1 VALUES (0xA2E6),(0xFEF7); +SELECT hex(a) FROM t1 ORDER BY a; +hex(a) +A2E6 +FEF7 +DROP TABLE t1; diff --git a/mysql-test/r/ctype_gb2312.result b/mysql-test/r/ctype_gb2312.result new file mode 100644 index 00000000000..314c336bab9 --- /dev/null +++ b/mysql-test/r/ctype_gb2312.result @@ -0,0 +1,167 @@ +drop table if exists t1; +SET @test_character_set= 'gb2312'; +SET @test_collation= 'gb2312_chinese_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) gb2312_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) gb2312_chinese_ci YES MUL NULL +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; +SET NAMES gb2312; +SET collation_connection='gb2312_chinese_ci'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gb2312_chinese_ci 6109 +gb2312_chinese_ci 61 +gb2312_chinese_ci 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gb2312_chinese_ci +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +gb2312_chinese_ci +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET collation_connection='gb2312_bin'; +create table t1 select repeat('a',4000) a; +delete from t1; +insert into t1 values ('a'), ('a '), ('a\t'); +select collation(a),hex(a) from t1 order by a; +collation(a) hex(a) +gb2312_bin 6109 +gb2312_bin 61 +gb2312_bin 6120 +drop table t1; +create table t1 engine=innodb select repeat('a',50) as c1; +alter table t1 add index(c1(5)); +insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); +select collation(c1) from t1 limit 1; +collation(c1) +gb2312_bin +select c1 from t1 where c1 like 'abcdef%' order by c1; +c1 +abcdefg +select c1 from t1 where c1 like 'abcde1%' order by c1; +c1 +abcde100 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde11%' order by c1; +c1 +abcde110 +abcde111 +select c1 from t1 where c1 like 'abcde111%' order by c1; +c1 +abcde111 +drop table t1; +select @@collation_connection; +@@collation_connection +gb2312_bin +create table t1 ROW_FORMAT=DYNAMIC select repeat('a',50) as c1 ; +insert into t1 values('abcdef'); +insert into t1 values('_bcdef'); +insert into t1 values('a_cdef'); +insert into t1 values('ab_def'); +insert into t1 values('abc_ef'); +insert into t1 values('abcd_f'); +insert into t1 values('abcde_'); +select c1 as c1u from t1 where c1 like 'ab\_def'; +c1u +ab_def +select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; +c2h +ab_def +drop table t1; +SET NAMES gb2312; +CREATE TABLE t1 (a text) character set gb2312; +INSERT INTO t1 VALUES (0xA2A1),(0xD7FE); +SELECT hex(a) FROM t1 ORDER BY a; +hex(a) +A2A1 +D7FE +DROP TABLE t1; diff --git a/mysql-test/r/have_euckr.require b/mysql-test/r/have_euckr.require new file mode 100644 index 00000000000..0771ceec570 --- /dev/null +++ b/mysql-test/r/have_euckr.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +euckr_korean_ci euckr 19 Yes Yes 1 diff --git a/mysql-test/r/have_gb2312.require b/mysql-test/r/have_gb2312.require new file mode 100644 index 00000000000..9bcb7c94a14 --- /dev/null +++ b/mysql-test/r/have_gb2312.require @@ -0,0 +1,2 @@ +Collation Charset Id Default Compiled Sortlen +gb2312_chinese_ci gb2312 24 Yes Yes 1 diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test new file mode 100644 index 00000000000..56939817b2f --- /dev/null +++ b/mysql-test/t/ctype_euckr.test @@ -0,0 +1,33 @@ +-- source include/have_euckr.inc + +# +# Tests with the euckr character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET @test_character_set= 'euckr'; +SET @test_collation= 'euckr_korean_ci'; +-- source include/ctype_common.inc + +SET NAMES euckr; +SET collation_connection='euckr_korean_ci'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc +SET collation_connection='euckr_bin'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc + +# +# Bug#15377 Valid multibyte sequences are truncated on INSERT +# +SET NAMES euckr; +CREATE TABLE t1 (a text) character set euckr; +INSERT INTO t1 VALUES (0xA2E6),(0xFEF7); +SELECT hex(a) FROM t1 ORDER BY a; +DROP TABLE t1; + +# End of 4.1 tests diff --git a/mysql-test/t/ctype_gb2312.test b/mysql-test/t/ctype_gb2312.test new file mode 100644 index 00000000000..835818d441c --- /dev/null +++ b/mysql-test/t/ctype_gb2312.test @@ -0,0 +1,33 @@ +-- source include/have_gb2312.inc + +# +# Tests with the gb2312 character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET @test_character_set= 'gb2312'; +SET @test_collation= 'gb2312_chinese_ci'; +-- source include/ctype_common.inc + +SET NAMES gb2312; +SET collation_connection='gb2312_chinese_ci'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc +SET collation_connection='gb2312_bin'; +-- source include/ctype_filesort.inc +-- source include/ctype_innodb_like.inc +-- source include/ctype_like_escape.inc + +# +# Bug#15377 Valid multibyte sequences are truncated on INSERT +# +SET NAMES gb2312; +CREATE TABLE t1 (a text) character set gb2312; +INSERT INTO t1 VALUES (0xA2A1),(0xD7FE); +SELECT hex(a) FROM t1 ORDER BY a; +DROP TABLE t1; + +# End of 4.1 tests diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index f15e97de5be..2863b192f50 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8635,6 +8635,41 @@ my_mb_wc_euc_kr(CHARSET_INFO *cs __attribute__((unused)), } +/* + Returns well formed length of a EUC-KR string. +*/ +static uint +my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, + uint pos, int *error) +{ + const char *b0= b; + const char *emb= e - 1; /* Last possible end of an MB character */ + + *error= 0; + while (pos-- && b < e) + { + if ((uchar) b[0] < 128) + { + /* Single byte ascii character */ + b++; + } + else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + *error= 1; + break; + } + } + return (uint) (b - b0); +} + + static MY_COLLATION_HANDLER my_collation_ci_handler = { NULL, /* init */ @@ -8655,7 +8690,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_euc_kr, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_euckr, my_lengthsp_8bit, my_numcells_8bit, my_mb_wc_euc_kr, /* mb_wc */ diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index 0cbad2d1c55..52dd61a8462 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5686,6 +5686,41 @@ my_mb_wc_gb2312(CHARSET_INFO *cs __attribute__((unused)), } +/* + Returns well formed length of a EUC-KR string. +*/ +static uint +my_well_formed_len_gb2312(CHARSET_INFO *cs __attribute__((unused)), + const char *b, const char *e, + uint pos, int *error) +{ + const char *b0= b; + const char *emb= e - 1; /* Last possible end of an MB character */ + + *error= 0; + while (pos-- && b < e) + { + if ((uchar) b[0] < 128) + { + /* Single byte ascii character */ + b++; + } + else if (b < emb && isgb2312head(*b) && isgb2312tail(b[1])) + { + /* Double byte character */ + b+= 2; + } + else + { + /* Wrong byte sequence */ + *error= 1; + break; + } + } + return (uint) (b - b0); +} + + static MY_COLLATION_HANDLER my_collation_ci_handler = { NULL, /* init */ @@ -5706,7 +5741,7 @@ static MY_CHARSET_HANDLER my_charset_handler= mbcharlen_gb2312, my_numchars_mb, my_charpos_mb, - my_well_formed_len_mb, + my_well_formed_len_gb2312, my_lengthsp_8bit, my_numcells_8bit, my_mb_wc_gb2312, /* mb_wc */ From e1c614134078b23934555bd76c6cdbd039d8bc28 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 19 Dec 2005 15:52:10 +0400 Subject: [PATCH 02/16] Bug#15581: COALESCE function truncates mutli-byte TINYTEXT values field.cc: BLOB variations have number-in-bytes limit, unlike CHAR/VARCHAR which have number-of-characters limits. A tinyblob column can store up to 255 bytes. In the case of basic Latin letters (which use 1 byte per character) we can store up to 255 characters in a tinyblob column. When passing an utf8 tinyblob column as an argument into a function (e.g. COALESCE) we need to reserve 3*255 bytes. I.e. multiply length in bytes to mbcharlen for the character set. Although in reality a tinyblob column can never be 3*255 bytes long, we need to set max_length to multiply to make fix_length_and_dec() of the function-caller (e.g. COALESCE) calculate the correct max_length for the column being created. ctype_utf8.result, ctype_utf8.test: Adding test case. mysql-test/t/ctype_utf8.test: Adding test case. mysql-test/r/ctype_utf8.result: Adding test case. sql/field.cc: Bug#15581: COALESCE function truncates mutli-byte TINYTEXT values BLOB variations have byte limits, unlike CHAR/VARCHAR which have number-of-character limits. It means tinyblob can store up to 255 bytes. All of them can be basic latin letters which use 1 byte per character. I.e. we can store up to 255 characters in a tinyblob column. When passing a tinyblob column as an argument into a function (for example COALESCE or CONCAT) we need to reserve 3*255 bytes in the case of utf-8. I.e. multiply length in bytes to mbcharlen for the character set. --- mysql-test/r/ctype_utf8.result | 8 ++++++++ mysql-test/t/ctype_utf8.test | 10 ++++++++++ sql/field.cc | 6 +++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 03d3ab9f22e..cf9426e6b21 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1070,3 +1070,11 @@ char(a) 1 2 drop table t1; +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +LENGTH(bug) +100 +DROP TABLE t2; +DROP TABLE t1; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 8c0e03c0cd3..01bffe9492e 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -882,4 +882,14 @@ set names utf8; select distinct char(a) from t1; drop table t1; +# +# Bug#15581: COALESCE function truncates mutli-byte TINYTEXT values +# +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +DROP TABLE t2; +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/field.cc b/sql/field.cc index abb5297f458..b1d9167aee2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6949,11 +6949,11 @@ uint32 Field_blob::max_length() switch (packlength) { case 1: - return 255; + return 255 * field_charset->mbmaxlen; case 2: - return 65535; + return 65535 * field_charset->mbmaxlen; case 3: - return 16777215; + return 16777215 * field_charset->mbmaxlen; case 4: return (uint32) 4294967295U; default: From 2dcedd9cbc4effee5a1c7e4c8045f2e8adced065 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 6 Jan 2006 21:42:17 +0200 Subject: [PATCH 03/16] Fixes during review of new pushed code: Remove wrong fix for Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash Safety fix for bug #13855 "select distinct with group by caused server crash" client/mysqlimport.c: Remove not used variable myisam/myisam_ftdump.c: Fixed compiler warning sql/item_cmpfunc.cc: Removed compiler warning sql/sql_handler.cc: Remove wrong fix for Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash. It's better to let mysql_lock_tables reopen the TABLE object in case of OPTIMIZE TABLE and fix items AFTER mysql_lock_table() instead of before sql/sql_select.cc: Safety fix for bug #13855 "select distinct with group by caused server crash" The previous patch only removed the symptomps, this fix removed the cause of the problem (Which was that not all hidden_fields was stored in the temporary table) --- client/mysqlimport.c | 1 - myisam/myisam_ftdump.c | 2 +- sql/item_cmpfunc.cc | 2 +- sql/sql_handler.cc | 46 +++++++++++------------------------------- sql/sql_select.cc | 9 ++++++++- 5 files changed, 22 insertions(+), 38 deletions(-) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 0932cf7432a..2dcb1d4eb6d 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -252,7 +252,6 @@ static int write_to_table(char *filename, MYSQL *sock) { char tablename[FN_REFLEN], hard_path[FN_REFLEN], sql_statement[FN_REFLEN*16+256], *end; - my_bool local_file; DBUG_ENTER("write_to_table"); DBUG_PRINT("enter",("filename: %s",filename)); diff --git a/myisam/myisam_ftdump.c b/myisam/myisam_ftdump.c index 838f90feae5..005d15376fb 100644 --- a/myisam/myisam_ftdump.c +++ b/myisam/myisam_ftdump.c @@ -66,7 +66,7 @@ int main(int argc,char *argv[]) struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ MY_INIT(argv[0]); - if (error=handle_options(&argc, &argv, my_long_options, get_one_option)) + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(error); if (count || dump) verbose=0; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 107a17815ae..db6c4d9789b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -659,7 +659,7 @@ bool Item_func_nullif::is_null() { if (!(this->*cmp_func)()) - return null_value=1; + return (null_value= 1); return 0; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 28e94d1a477..58b75e667b5 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -380,27 +380,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->real_name, hash_tables->alias, table)); - /* Table might have been flushed. */ - if (table && (table->version != refresh_version)) - { - /* - We must follow the thd->handler_tables chain, as we need the - address of the 'next' pointer referencing this table - for close_thread_table(). - */ - for (table_ptr= &(thd->handler_tables); - *table_ptr && (*table_ptr != table); - table_ptr= &(*table_ptr)->next) - {} - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, table_ptr)) - { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); - } - VOID(pthread_mutex_unlock(&LOCK_open)); - table= hash_tables->table= NULL; - } if (!table) { /* @@ -447,11 +426,16 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; + HANDLER_TABLES_HACK(thd); + lock= mysql_lock_tables(thd, &tables->table, 1, 0); + HANDLER_TABLES_HACK(thd); + + if (!lock) + goto err0; // mysql_lock_tables() printed error message already + if (cond && cond->fix_fields(thd,tables)) goto err0; - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - if (keyname) { if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) @@ -462,6 +446,11 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } table->file->index_init(keyno); } + + byte *key; + uint key_len; + LINT_INIT(key); + LINT_INIT(key_len); if (insert_fields(thd,tables,tables->db,tables->alias,&it)) goto err0; @@ -469,17 +458,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, select_limit+=offset_limit; send_fields(thd,list,1); - HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0); - HANDLER_TABLES_HACK(thd); - - byte *key; - uint key_len; - LINT_INIT(key); - LINT_INIT(key_len); - if (!lock) - goto err0; // mysql_lock_tables() printed error message already - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it for (num_rows=0; num_rows < select_limit; ) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6dd68a60f88..32658f92416 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4082,7 +4082,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, *(reg_field++) =new_field; } if (!--hidden_field_count) + { hidden_null_count=null_count; + /* + We need to update hidden_field_count as we may have stored group + functions with constant arguments + */ + param->hidden_field_count= (uint) (reg_field - table->field); + } } DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= (uint) (reg_field - table->field); @@ -4270,7 +4277,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, } } - if (distinct) + if (distinct && field_count != param->hidden_field_count) { /* Create an unique key or an unique constraint over all columns From e12bc697db8509602cd7c765fbd95d8543ad6308 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 9 Jan 2006 11:10:49 +0200 Subject: [PATCH 04/16] After merge fix (Lines lost in manual merge) --- sql/sql_handler.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index a69bf04cc48..765a057f740 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -454,6 +454,9 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (insert_fields(thd,tables,tables->db,tables->alias,&it)) goto err0; + select_limit+=offset_limit; + protocol->send_fields(&list,1); + /* In ::external_lock InnoDB resets the fields which tell it that the handle is used in the HANDLER interface. Tell it again that From af024409afac7b9ded1f5c431e08f3b26699bcf6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Jan 2006 19:13:12 +0200 Subject: [PATCH 05/16] Re-run fix-fields on condition if table was reopened in HANDLERREAD sql/sql_base.cc: Added more comments sql/sql_handler.cc: Re-run fix-fields on condition if table was reopened --- sql/sql_base.cc | 20 ++++++++++++++++---- sql/sql_handler.cc | 11 ++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c8443948a4a..ea013bb4e1e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1012,10 +1012,20 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name) /**************************************************************************** -** Reopen an table because the definition has changed. The date file for the -** table is already closed. -** Returns 0 if ok. -** If table can't be reopened, the entry is unchanged. + Reopen an table because the definition has changed. The date file for the + table is already closed. + + SYNOPSIS + reopen_table() + table Table to be opened + locked 1 if we have already a lock on LOCK_open + + NOTES + table->query_id will be 0 if table was reopened + + RETURN + 0 ok + 1 error ('table' is unchanged if table couldn't be reopened) ****************************************************************************/ bool reopen_table(TABLE *table,bool locked) @@ -1085,8 +1095,10 @@ bool reopen_table(TABLE *table,bool locked) (*field)->table_name=table->table_name; } for (key=0 ; key < table->keys ; key++) + { for (part=0 ; part < table->key_info[key].usable_key_parts ; part++) table->key_info[key].key_part[part].field->table= table; + } VOID(pthread_cond_broadcast(&COND_refresh)); error=0; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 765a057f740..1c5381a9fa0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -437,9 +437,14 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already - if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) - goto err0; + if (cond) + { + if (table->query_id != thd->query_id) + cond->cleanup(); // File was reopened + if ((!cond->fixed && + cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)) + goto err0; + } if (keyname) { From 593bed0d929cdc2827439d4697ce6f4b2bc9d941 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jan 2006 22:49:43 +0300 Subject: [PATCH 06/16] Fixed bug #15633: Evaluation of Item_equal for non-const table caused wrong select result Item equal objects are employed only at the optimize phase. Usually they are not supposed to be evaluated. Yet in some cases we call the method val_int() for them. Here we have to take care of restricting the predicate such an object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik. Added a check for field's table being const in Item_equal::val_int(). If the field's table is not const val_int() just skips that field when evaluating Item_equal. mysql-test/t/select.test: Added test case for bug #15633: Evaluation of Item_equal for non-const table caused wrong select result mysql-test/r/select.result: Added test case for bug #15633: Evaluation of Item_equal for non-const table caused wrong select result mysql-test/r/func_group.result: Corrected test result for bug #12882 after fix for bug#15633 sql/item_cmpfunc.h: Fixed bug #15633: Evaluation of Item_equal for non-const table caused wrong select result Added comment about fields from non-const tables in class description. sql/item_cmpfunc.cc: Fixed bug #15633: Evaluation of Item_equal for non-const table caused wrong select result Added check for field's table being const in Item_equal::val_int(). --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/select.result | 13 +++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/item_cmpfunc.cc | 11 ++++++++--- sql/item_cmpfunc.h | 5 +++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 2b0176179ed..cfa4cc0ef68 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -865,6 +865,7 @@ select 1, min(a) from t1m where 1=99; 1 NULL select 1, min(1) from t1m where a=99; 1 min(1) +1 NULL select 1, min(1) from t1m where 1=99; 1 min(1) 1 NULL @@ -876,6 +877,7 @@ select 1, max(a) from t1m where 1=99; 1 NULL select 1, max(1) from t1m where a=99; 1 max(1) +1 NULL select 1, max(1) from t1m where 1=99; 1 max(1) 1 NULL diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 598ea2b10d1..198493d0a02 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3337,3 +3337,16 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index 1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 DROP TABLE t1,t2,t3; +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +f3 +NULL +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +f2 +1 +drop table t1,t2,t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a73d08f5f18..595362dbb65 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2805,3 +2805,17 @@ EXPLAIN SELECT t2.key_a,foo WHERE t2.key_a=2 and key_b=5; DROP TABLE t1,t2,t3; + +# +# Bug #15633 Evaluation of Item_equal for non-const table caused wrong +# select result +# +create table t1 (f1 int unique); +create table t2 (f2 int unique); +create table t3 (f3 int unique); +insert into t1 values(1),(2); +insert into t2 values(1),(2); +insert into t3 values(1),(NULL); +select * from t3 where f3 is null; +select t2.f2 from t1 left join t2 on f1=f2 join t3 on f1=f3 where f1=1; +drop table t1,t2,t3; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 15614a32c39..306277aa438 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3765,6 +3765,7 @@ void Item_equal::update_used_tables() longlong Item_equal::val_int() { + Item_field *item_field; if (cond_false) return 0; List_iterator_fast it(fields); @@ -3772,10 +3773,14 @@ longlong Item_equal::val_int() if ((null_value= item->null_value)) return 0; eval_item->store_value(item); - while ((item= it++)) + while ((item_field= it++)) { - if ((null_value= item->null_value) || eval_item->cmp(item)) - return 0; + /* Skip fields of non-const tables. They haven't been read yet */ + if (item_field->field->table->const_table) + { + if ((null_value= item_field->null_value) || eval_item->cmp(item_field)) + return 0; + } } return 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index bfd32223d4c..89d117ee4ec 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1150,6 +1150,11 @@ public: are deleted in the end of execution. All changes made to these objects need not be registered in the list of changes of the parse tree and do not harm PS/SP re-execution. + + Item equal objects are employed only at the optimize phase. Usually they are + not supposed to be evaluated. Yet in some cases we call the method val_int() + for them. We have to take care of restricting the predicate such an + object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik. */ class Item_equal: public Item_bool_func From ddcc6d7bd445617b3e0bfaff1247a453d21d48f0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jan 2006 23:16:21 +0300 Subject: [PATCH 07/16] Fixed bug #15347: Wrong result of subselect when records cache and set functions are involved. When subselect is a join with set functions and no record have been found in it, end_send_group() sets null_row for all tables in order aggregate functions to calculate their values correctly. Normally this null_row flag is cleared for each table in sub_select(), but flush_cached_records() doesn't do so. Due to this all fields from the table processed by flush_cached_records() are always evaluated as nulls and whole select produces wrong result. flush_cached_records() now clears null_row flag at the very beginning. mysql-test/t/select.test: Added test case for bug #15347: Wrong result of subselect when records cache and set functions are involved mysql-test/r/select.result: Added test case for bug #15347: Wrong result of subselect when records cache and set functions are involved sql/sql_select.cc: Fixed bug #15347: Wrong result of subselect when records cache and set functions are involved flush_cached_records() now clears null_row flag at the very beginning. --- mysql-test/r/select.result | 11 +++++++++++ mysql-test/t/select.test | 13 +++++++++++++ sql/sql_select.cc | 1 + 3 files changed, 25 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 598ea2b10d1..b9b0c1ee9e8 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3337,3 +3337,14 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY PRIMARY 4 const 1 Using index 1 SIMPLE t3 const PRIMARY PRIMARY 8 const,const 1 DROP TABLE t1,t2,t3; +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +f1 count +1 0 +2 3 +drop table t1,t2,t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a73d08f5f18..6044982d57c 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2805,3 +2805,16 @@ EXPLAIN SELECT t2.key_a,foo WHERE t2.key_a=2 and key_b=5; DROP TABLE t1,t2,t3; + +# +# Bug#15347 Wrong result of subselect when records cache and set functions +# are involved +# +create table t1 (f1 int); +insert into t1 values(1),(2); +create table t2 (f2 int, f3 int, key(f2)); +insert into t2 values(1,1),(2,2); +create table t3 (f4 int not null); +insert into t3 values (2),(2),(2); +select f1,(select count(*) from t2,t3 where f2=f1 and f3=f4) as count from t1; +drop table t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8538372d607..4573598cd29 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9853,6 +9853,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) int error; READ_RECORD *info; + join_tab->table->null_row= 0; if (!join_tab->cache.records) return NESTED_LOOP_OK; /* Nothing to do */ if (skip_last) From 4e2e0c6d53ea561005b2b9d600d3ba0e0fe11f05 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Jan 2006 23:39:09 +0300 Subject: [PATCH 08/16] Fixed bug #15538: unchecked table absence caused server crash. Absence of table in left part of LEFT/RIGHT join wasn't checked before name resolution which resulted in NULL dereferencing and server crash. Modified rules: "table_ref LEFT opt_outer JOIN_SYM table_ref" and "table_ref RIGHT opt_outer JOIN_SYM table_ref" NULL check is moved before push_new_name_resolution_context() sql/sql_yacc.yy: Fixed bug #15538: unchecked table absence caused server crash. Modified rules: "table_ref LEFT opt_outer JOIN_SYM table_ref" and "table_ref RIGHT opt_outer JOIN_SYM table_ref" NULL check is moved before push_new_name_resolution_context() mysql-test/r/select.result: Added test case for bug #15538: unchecked table absence caused server crash. mysql-test/t/select.test: Added test case for bug #15538: unchecked table absence caused server crash. --- mysql-test/r/select.result | 2 ++ mysql-test/t/select.test | 6 ++++++ sql/sql_yacc.yy | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index e2c4609d902..943ab88223c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3345,3 +3345,5 @@ select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; f1 f2 f2 NULL a NULL drop table t1,t2; +select * from (select * left join t on f1=f2) tt; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'on f1=f2) tt' at line 1 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index a85b82a7767..53f82690888 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2815,3 +2815,9 @@ create table t2 (f2 char not null); insert into t2 values('b'); select * from t1 left join t2 on f1=t2.f2 where t1.f2='a'; drop table t1,t2; + +# +# Bug#15538 unchecked table absense caused server crash. +# +--error 1064 +select * from (select * left join t on f1=f2) tt; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 25e10362ece..f1a00fca383 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5248,13 +5248,13 @@ join_table: | table_ref LEFT opt_outer JOIN_SYM table_ref ON { + YYERROR_UNLESS($1 && $5); /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; } expr { - YYERROR_UNLESS($1 && $5); add_join_on($5,$8); Lex->pop_context(); $5->outer_join|=JOIN_TYPE_LEFT; @@ -5279,6 +5279,7 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_ref ON { + YYERROR_UNLESS($1 && $5); /* Change the current name resolution context to a local context. */ if (push_new_name_resolution_context(YYTHD, $1, $5)) YYABORT; @@ -5286,7 +5287,6 @@ join_table: expr { LEX *lex= Lex; - YYERROR_UNLESS($1 && $5); if (!($$= lex->current_select->convert_right_join())) YYABORT; add_join_on($$, $8); From 8d9ffc6ad4ad487cd7adfe8d8bb2028cf0920a44 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 10:48:27 +0300 Subject: [PATCH 09/16] BUG#16166, "Can't use index_merge with FORCE INDEX": adjust the heurstics check to take into account that "FORCE INDEX" disables full table scans, and not range/index_merge scans. (with post-review fixes) mysql-test/r/index_merge.result: Testcase for BUG#16166 mysql-test/t/index_merge.test: Testcase for BUG#16166 sql/sql_select.cc: BUG#16166: "Can't use index_merge with FORCE INDEX": adjust the heuristics check: if (force-index-is-used && there-is-possible-ref-access && + THERE IS NO POSSIBLE RANGE/INDEX_MERGE ACCESS) { ... --- mysql-test/r/index_merge.result | 18 +++++++++++++++++ mysql-test/t/index_merge.test | 30 ++++++++++++++++++++++++++++ sql/sql_select.cc | 35 ++++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index d039d5a04c9..db87253e19a 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -384,3 +384,21 @@ max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.ke 8186 set join_buffer_size= @save_join_buffer_size; drop table t0, t1, t2, t3, t4; +CREATE TABLE t1 ( +cola char(3) not null, colb char(3) not null, filler char(200), +key(cola), key(colb) +); +INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +select count(*) from t1; +count(*) +8704 +explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where +explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where +drop table t1; diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index 42175a757c2..10512902409 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -327,3 +327,33 @@ set join_buffer_size= @save_join_buffer_size; drop table t0, t1, t2, t3, t4; +# BUG#16166 +CREATE TABLE t1 ( + cola char(3) not null, colb char(3) not null, filler char(200), + key(cola), key(colb) +); +INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ'); + +--disable_query_log +let $1=9; +while ($1) +{ + eval INSERT INTO t1 SELECT * from t1 WHERE cola = 'foo'; + dec $1; +} + +let $1=13; +while ($1) +{ + eval INSERT INTO t1 SELECT * from t1 WHERE cola <> 'foo'; + dec $1; +} + +--enable_query_log + +OPTIMIZE TABLE t1; +select count(*) from t1; +explain select * from t1 WHERE cola = 'foo' AND colb = 'bar'; +explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar'; +drop table t1; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c282a5bd42c..4a31a297c25 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3471,13 +3471,32 @@ best_access_path(JOIN *join, parts of the row from any of the used index. This is because table scans uses index and we would not win anything by using a table scan. + + A word for word translation of the below if-statement in psergey's + understanding: we check if we should use table scan if: + (1) The found 'ref' access produces more records than a table scan + (or index scan, or quick select), or 'ref' is more expensive than + any of them. + (2) This doesn't hold: the best way to perform table scan is to to perform + 'range' access using index IDX, and the best way to perform 'ref' + access is to use the same index IDX, with the same or more key parts. + (note: it is not clear how this rule is/should be extended to + index_merge quick selects) + (3) See above note about InnoDB. + (4) NOT ("FORCE INDEX(...)" is used for table and there is 'ref' access + path, but there is no quick select) + If the condition in the above brackets holds, then the only possible + "table scan" access method is ALL/index (there is no quick select). + Since we have a 'ref' access path, and FORCE INDEX instructs us to + choose it over ALL/index, there is no need to consider a full table + scan. */ - if ((records >= s->found_records || best > s->read_time) && - !(s->quick && best_key && s->quick->index == best_key->key && - best_max_key_part >= s->table->quick_key_parts[best_key->key]) && - !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && - ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key)) + if ((records >= s->found_records || best > s->read_time) && // (1) + !(s->quick && best_key && s->quick->index == best_key->key && // (2) + best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2) + !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3) + ! s->table->used_keys.is_clear_all() && best_key) && // (3) + !(s->table->force_index && best_key && !s->quick)) // (4) { // Check full join ha_rows rnd_records= s->found_records; /* @@ -4460,13 +4479,15 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, parts of the row from any of the used index. This is because table scans uses index and we would not win anything by using a table scan. + (see comment in best_access_path() for more details on the below + condition) */ if ((records >= s->found_records || best > s->read_time) && !(s->quick && best_key && s->quick->index == best_key->key && best_max_key_part >= s->table->quick_key_parts[best_key->key]) && !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key)) + !(s->table->force_index && best_key & !s->quick)) { // Check full join ha_rows rnd_records= s->found_records; /* From 9878a35a6a170720d7b09e55790f2e189bb1d636 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 11:11:16 +0300 Subject: [PATCH 10/16] Fix typo bug in previous cset --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4a31a297c25..e8f2cb2c6a0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4487,7 +4487,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, best_max_key_part >= s->table->quick_key_parts[best_key->key]) && !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && ! s->table->used_keys.is_clear_all() && best_key) && - !(s->table->force_index && best_key & !s->quick)) + !(s->table->force_index && best_key && !s->quick)) { // Check full join ha_rows rnd_records= s->found_records; /* From cd1f75e9cb3aeb61c31a739db515065bbe6f4df4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 13:08:49 +0400 Subject: [PATCH 11/16] ctype_utf8.result: After merge fix: fixing order of results. mysql-test/r/ctype_utf8.result: After merge fix: fixing order of results. --- mysql-test/r/ctype_utf8.result | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index fee561941f0..b2a22036cb5 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -1058,6 +1058,14 @@ char(a) 1 2 drop table t1; +CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); +INSERT INTO t1 VALUES(REPEAT('a', 100)); +CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; +SELECT LENGTH(bug) FROM t2; +LENGTH(bug) +100 +DROP TABLE t2; +DROP TABLE t1; CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8; INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa'); SELECT id FROM t1; @@ -1167,11 +1175,3 @@ set @a:=null; execute my_stmt using @a; a b drop table if exists t1; -CREATE TABLE t1 (t TINYTEXT CHARACTER SET utf8); -INSERT INTO t1 VALUES(REPEAT('a', 100)); -CREATE TEMPORARY TABLE t2 SELECT COALESCE(t) AS bug FROM t1; -SELECT LENGTH(bug) FROM t2; -LENGTH(bug) -100 -DROP TABLE t2; -DROP TABLE t1; From 46fdcba4f13ad54cb617dd3a649ee02f64bb8652 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 16:05:46 +0400 Subject: [PATCH 12/16] sql_show.cc: after-merge fix for bug#15581 COALESCE function truncates mutli-byte TINYTEXT values sql/sql_show.cc: after-merge fix for bug#15581 COALESCE function truncates mutli-byte TINYTEXT values , --- sql/sql_show.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d15df686e40..59008b1b77f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2623,12 +2623,15 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type field->real_type() == MYSQL_TYPE_STRING) // For binary type { + uint32 octet_max_length= field->max_length(); + if (octet_max_length != (uint32) 4294967295U) + octet_max_length /= field->charset()->mbmaxlen; longlong char_max_len= is_blob ? - (longlong) field->max_length() / field->charset()->mbminlen : - (longlong) field->max_length() / field->charset()->mbmaxlen; + (longlong) octet_max_length / field->charset()->mbminlen : + (longlong) octet_max_length / field->charset()->mbmaxlen; table->field[8]->store(char_max_len, TRUE); table->field[8]->set_notnull(); - table->field[9]->store((longlong) field->max_length(), TRUE); + table->field[9]->store((longlong) octet_max_length, TRUE); table->field[9]->set_notnull(); } From 2946f9a64f664293010777e422e7b66058ce323a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 15:10:12 +0200 Subject: [PATCH 13/16] NetWare specific change to increase thread stack size. Changes to Netware specific mysqld_safe.c include/config-netware.h: NetWare specific change to increase thread stack size. innobase/os/os0thread.c: NetWare specific change to increase thread stack size. netware/mysqld_safe.c: NetWare specific change to make multiple mysqld_safe instances work when called through a NCF file. sql/mysqld.cc: NetWare specific change to increase thread stack size. --- include/config-netware.h | 3 +++ innobase/os/os0thread.c | 9 +++++++++ netware/mysqld_safe.c | 42 ++++++++++++++-------------------------- sql/mysqld.cc | 5 +++++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/include/config-netware.h b/include/config-netware.h index e07e972ba4b..43ee05e39ee 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -92,6 +92,9 @@ extern "C" { /* On NetWare, stack grows towards lower address*/ #define STACK_DIRECTION -1 +/* On NetWare, we need to set stack size for threads, otherwise default 16K is used */ +#define NW_THD_STACKSIZE 65536 + /* On NetWare, to fix the problem with the deletion of open files */ #define CANT_DELETE_OPEN_FILES 1 diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 59d0fdbd8c9..cb72310f23d 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -147,6 +147,15 @@ os_thread_create( "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); exit(1); } +#endif +#ifdef __NETWARE__ + ret = pthread_attr_setstacksize(&attr, + (size_t) NW_THD_STACKSIZE); + if (ret) { + fprintf(stderr, + "InnoDB: Error: pthread_attr_setstacksize returned %d\n", ret); + exit(1); + } #endif os_mutex_enter(os_sync_mutex); os_thread_count++; diff --git a/netware/mysqld_safe.c b/netware/mysqld_safe.c index dbb49882140..5f65e2f45b7 100644 --- a/netware/mysqld_safe.c +++ b/netware/mysqld_safe.c @@ -252,51 +252,39 @@ void finish_defaults() ******************************************************************************/ void read_defaults(arg_list_t *pal) { - arg_list_t al; - char defaults_file[PATH_MAX]; char mydefaults[PATH_MAX]; + char mydefaults_command[3*PATH_MAX]; char line[PATH_MAX]; FILE *fp; - // defaults output file - snprintf(defaults_file, PATH_MAX, "%s/bin/defaults.out", basedir); - remove(defaults_file); - - // mysqladmin file + // my_print_defaults file snprintf(mydefaults, PATH_MAX, "%s/bin/my_print_defaults", basedir); - // args - init_args(&al); - add_arg(&al, mydefaults); - if (default_option[0]) add_arg(&al, default_option); - add_arg(&al, "mysqld"); - add_arg(&al, "server"); - add_arg(&al, "mysqld_safe"); - add_arg(&al, "safe_mysqld"); - - spawn(mydefaults, &al, TRUE, NULL, defaults_file, NULL); - - free_args(&al); - + // args to my_print_defaults + if (default_option[0]) + { + snprintf(mydefaults_command, 3*PATH_MAX, "%s %s mysqld server mysqld_safe safe_mysqld", mydefaults, default_option); + } + else + { + snprintf(mydefaults_command, 3*PATH_MAX, "%s mysqld server mysqld_safe safe_mysqld", mydefaults); + } // gather defaults - if((fp = fopen(defaults_file, "r")) != NULL) + if((fp = popen(mydefaults_command, "r")) != NULL) { while(fgets(line, PATH_MAX, fp)) { char *p; // remove end-of-line character - if ((p = strrchr(line, '\n')) != NULL) *p = '\0'; + if ((p = strrchr(line, '\n')) != NULL) + *p = '\0'; // add the option as an argument add_arg(pal, line); } - - fclose(fp); + pclose(fp); } - - // remove file - remove(defaults_file); } /****************************************************************************** diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f7df7233795..00bcdbf7132 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2401,6 +2401,11 @@ You should consider changing lower_case_table_names to 1 or 2", thread_stack= stack_size; } } +#endif +#ifdef __NETWARE__ + /* Increasing stacksize of threads on NetWare */ + + pthread_attr_setstacksize(&connection_attrib, NW_THD_STACKSIZE); #endif if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR); From 5c28e9c8d0f79931e39c9ad1eb51434328e702cd Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 20:31:00 +0200 Subject: [PATCH 14/16] Fix for Netware build. --- netware/BUILD/compile-linux-tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools index 14422ea5a3f..fab92b8d4df 100755 --- a/netware/BUILD/compile-linux-tools +++ b/netware/BUILD/compile-linux-tools @@ -57,7 +57,7 @@ make cp extra/comp_err extra/comp_err.linux cp libmysql/conf_to_src libmysql/conf_to_src.linux #cp libmysql_r/conf_to_src libmysql_r/conf_to_src.linux -cp sql/gen_lex_hash sql/gen_lex_hash.linux +cp sql/.libs/gen_lex_hash sql/gen_lex_hash.linux cp strings/conf_to_src strings/conf_to_src.linux # Delete mysql_version.h From 0f4962c338716bbc72ba8dd7102052fcbcfd4f80 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 Jan 2006 20:49:47 +0200 Subject: [PATCH 15/16] Fixed a bug in merge. --- sql/sql_handler.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 3370a0a1957..e9e1e79daaf 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -426,9 +426,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, { if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - if ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)) - goto err0; + goto err0; } if (keyname) From c12a3dfefd29b3bb4a93fee4778e0e94b1e00871 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 13 Jan 2006 01:51:56 +0300 Subject: [PATCH 16/16] Fix for bug #12198 "Temporary table aliasing does not work inside stored functions". We should ignore alias when we check if table was already marked as temporary when we calculate set of tables to be prelocked. Otherwise we will erroneously treat tables which are used in same routine and have same name but different alias as non-temporary. mysql-test/r/sp.result: Added test for bug #12198 "Temporary table aliasing does not work inside stored functions" and other tests which cover handling of temporary tables in prelocked mode. mysql-test/t/sp.test: Added test for bug #12198 "Temporary table aliasing does not work inside stored functions" and other tests which cover handling of temporary tables in prelocked mode. sql/sp_head.cc: sp_head::merge_table_list(): We should ignore alias when we check if table was already marked as temporary when we calculate set of tables to be prelocked. Otherwise we will erroneously treat tables which are used in same routine and have same name but different alias as non-temporary. --- mysql-test/r/sp.result | 67 +++++++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 80 ++++++++++++++++++++++++++++++++++++++++-- sql/sp_head.cc | 31 +++++++++++----- 3 files changed, 168 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 231ca329f3d..6d231b35a89 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -918,6 +918,11 @@ drop function if exists f5| drop function if exists f6| drop function if exists f7| drop function if exists f8| +drop function if exists f9| +drop function if exists f10| +drop function if exists f11| +drop function if exists f12_1| +drop function if exists f12_2| drop view if exists v0| drop view if exists v1| drop view if exists v2| @@ -1087,6 +1092,62 @@ ERROR HY000: Table 't1' was not locked with LOCK TABLES select f4()| ERROR HY000: Table 't2' was not locked with LOCK TABLES unlock tables| +create function f9() returns int +begin +declare a, b int; +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +set a:= (select count(*) from t3); +set b:= (select count(*) from t3 t3_alias); +return a + b; +end| +select f9()| +f9() +6 +Warnings: +Note 1051 Unknown table 't3' +select f9() from t1 limit 1| +f9() +6 +create function f10() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 select id from t4; +return (select count(*) from t3); +end| +select f10()| +ERROR 42S02: Table 'test.t4' doesn't exist +create table t4 as select 1 as id| +select f10()| +f10() +1 +create function f11() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +return (select count(*) from t3 as a, t3 as b); +end| +select f11()| +ERROR HY000: Can't reopen table: 'a' +select f11() from t1| +ERROR HY000: Can't reopen table: 'a' +create function f12_1() returns int +begin +drop temporary table if exists t3; +create temporary table t3 (id int); +insert into t3 values (1), (2), (3); +return f12_2(); +end| +create function f12_2() returns int +return (select count(*) from t3)| +drop temporary table t3| +select f12_1()| +ERROR 42S02: Table 'test.t3' doesn't exist +select f12_1() from t1 limit 1| +ERROR 42S02: Table 'test.t3' doesn't exist drop function f0| drop function f1| drop function f2| @@ -1096,11 +1157,17 @@ drop function f5| drop function f6| drop function f7| drop function f8| +drop function f9| +drop function f10| +drop function f11| +drop function f12_1| +drop function f12_2| drop view v0| drop view v1| drop view v2| delete from t1 | delete from t2 | +drop table t4| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| drop procedure if exists ifac| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index fba3cfcbfbc..6aa27969299 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1154,6 +1154,11 @@ drop function if exists f5| drop function if exists f6| drop function if exists f7| drop function if exists f8| +drop function if exists f9| +drop function if exists f10| +drop function if exists f11| +drop function if exists f12_1| +drop function if exists f12_2| drop view if exists v0| drop view if exists v1| drop view if exists v2| @@ -1233,8 +1238,6 @@ create function f7() returns int select f6()| select id, f6() from t1| -# TODO Test temporary table handling - # # Let us test how new locking work with views # @@ -1318,6 +1321,73 @@ select * from v1, t1| select f4()| unlock tables| +# Tests for handling of temporary tables in functions. +# +# Unlike for permanent tables we should be able to create, use +# and drop such tables in functions. +# +# Simplest function using temporary table. It is also test case for bug +# #12198 "Temporary table aliasing does not work inside stored functions" +create function f9() returns int +begin + declare a, b int; + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + set a:= (select count(*) from t3); + set b:= (select count(*) from t3 t3_alias); + return a + b; +end| +# This will emit warning as t3 was not existing before. +select f9()| +select f9() from t1 limit 1| + +# Function which uses both temporary and permanent tables. +create function f10() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 select id from t4; + return (select count(*) from t3); +end| +# Check that we don't ignore completely tables used in function +--error ER_NO_SUCH_TABLE +select f10()| +create table t4 as select 1 as id| +select f10()| + +# Practical cases which we don't handle well (yet) +# +# Function which does not work because of well-known and documented +# limitation of MySQL. We can't use the several instances of the +# same temporary table in statement. +create function f11() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + return (select count(*) from t3 as a, t3 as b); +end| +--error ER_CANT_REOPEN_TABLE +select f11()| +--error ER_CANT_REOPEN_TABLE +select f11() from t1| +# We don't handle temporary tables used by nested functions well +create function f12_1() returns int +begin + drop temporary table if exists t3; + create temporary table t3 (id int); + insert into t3 values (1), (2), (3); + return f12_2(); +end| +create function f12_2() returns int + return (select count(*) from t3)| +# We need clean start to get error +drop temporary table t3| +--error ER_NO_SUCH_TABLE +select f12_1()| +--error ER_NO_SUCH_TABLE +select f12_1() from t1 limit 1| # Cleanup drop function f0| @@ -1329,11 +1399,17 @@ drop function f5| drop function f6| drop function f7| drop function f8| +drop function f9| +drop function f10| +drop function f11| +drop function f12_1| +drop function f12_2| drop view v0| drop view v1| drop view v2| delete from t1 | delete from t2 | +drop table t4| # End of non-bug tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a6e88c08789..8d0212a31da 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2992,7 +2992,14 @@ sp_restore_security_context(THD *thd, Security_context *backup) typedef struct st_sp_table { - LEX_STRING qname; /* Multi-set key: db_name\0table_name\0alias\0 */ + /* + Multi-set key: + db_name\0table_name\0alias\0 - for normal tables + db_name\0table_name\0 - for temporary tables + Note that in both cases we don't take last '\0' into account when + we count length of key. + */ + LEX_STRING qname; uint db_length, table_name_length; bool temp; /* true if corresponds to a temporary table */ thr_lock_type lock_type; /* lock type used for prelocking */ @@ -3062,10 +3069,14 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tname[tlen]= '\0'; /* - It is safe to store pointer to table list elements in hash, - since they are supposed to have the same lifetime. + We ignore alias when we check if table was already marked as temporary + (and therefore should not be prelocked). Otherwise we will erroneously + treat table with same name but with different alias as non-temporary. */ - if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen))) + if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) || + ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, + tlen - alen - 1)) && + tab->temp)) { if (tab->lock_type < table->lock_type) tab->lock_type= table->lock_type; // Use the table with the highest lock type @@ -3077,14 +3088,18 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) { if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) return FALSE; - tab->qname.length= tlen; - tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1); - if (!tab->qname.str) - return FALSE; if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && lex_for_tmp_check->query_tables == table && lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) + { tab->temp= TRUE; + tab->qname.length= tlen - alen - 1; + } + else + tab->qname.length= tlen; + tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1); + if (!tab->qname.str) + return FALSE; tab->table_name_length= table->table_name_length; tab->db_length= table->db_length; tab->lock_type= table->lock_type;