From 1b66efe9d625df7d4d88dbacb8b97a9976bcf449 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Jun 2006 18:21:34 -0700 Subject: [PATCH 01/42] Fixed some dsp files. Fixed make_win_src_distribution.sh to return back dsp files for yassl. VC++Files/client/mysqldump.dsp: my_user.c was missing. VC++Files/client/mysqldump_ia64.dsp: my_user.c was missing. VC++Files/sql/mysqld.dsp: my_user.c was missing. VC++Files/sql/mysqld_ia64.dsp: my_user.c was missing. extra/yassl/yassl.dsp: Added the YASSL_PREFIX flag. scripts/make_win_src_distribution.sh: Returned back dsp files from yassl. --- VC++Files/client/mysqldump.dsp | 4 ++++ VC++Files/client/mysqldump_ia64.dsp | 4 ++++ VC++Files/sql/mysqld.dsp | 4 ++++ VC++Files/sql/mysqld_ia64.dsp | 4 ++++ extra/yassl/yassl.dsp | 8 ++++---- scripts/make_win_src_distribution.sh | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/VC++Files/client/mysqldump.dsp b/VC++Files/client/mysqldump.dsp index 527d1eb0a74..09f0df15ceb 100644 --- a/VC++Files/client/mysqldump.dsp +++ b/VC++Files/client/mysqldump.dsp @@ -128,6 +128,10 @@ SOURCE=.\mysqldump.c !ENDIF +# End Source File +# Begin Source File + +SOURCE=..\sql-common\my_user.c # End Source File # End Target # End Project diff --git a/VC++Files/client/mysqldump_ia64.dsp b/VC++Files/client/mysqldump_ia64.dsp index 79a7059cae5..360d16ea8e4 100644 --- a/VC++Files/client/mysqldump_ia64.dsp +++ b/VC++Files/client/mysqldump_ia64.dsp @@ -131,6 +131,10 @@ SOURCE=.\mysqldump.c !ENDIF +# End Source File +# Begin Source File + +SOURCE=..\sql-common\my_user.c # End Source File # End Target # End Project diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index 817e3224ea4..d44e61d8399 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -2052,6 +2052,10 @@ SOURCE=.\unireg.cpp !ENDIF +# End Source File +# Begin Source File + +SOURCE=..\sql-common\my_user.c # End Source File # End Target # End Project diff --git a/VC++Files/sql/mysqld_ia64.dsp b/VC++Files/sql/mysqld_ia64.dsp index 310f48fcfb9..abf7ce4a4a2 100644 --- a/VC++Files/sql/mysqld_ia64.dsp +++ b/VC++Files/sql/mysqld_ia64.dsp @@ -2008,6 +2008,10 @@ SOURCE=.\unireg.cpp !ENDIF +# End Source File +# Begin Source File + +SOURCE=..\sql-common\my_user.c # End Source File # End Target # End Project diff --git a/extra/yassl/yassl.dsp b/extra/yassl/yassl.dsp index dc090512743..58c016da448 100644 --- a/extra/yassl/yassl.dsp +++ b/extra/yassl/yassl.dsp @@ -40,8 +40,8 @@ RSC=rc.exe # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MT /W3 /O2 /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "YASSL_PREFIX" /YX /FD /c +# ADD CPP /nologo /MT /W3 /O2 /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "YASSL_PREFIX" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -63,8 +63,8 @@ LIB32=link.exe -lib # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "YASSL_PREFIX" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "YASSL_PREFIX" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index c677db6a537..d9333540ab8 100644 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -203,7 +203,7 @@ copy_dir_files() print_debug "Creating directory '$arg'" mkdir $BASE/$arg fi - for i in *.c *.cpp *.h *.ih *.i *.ic *.asm *.def *.hpp *.yy \ + for i in *.c *.cpp *.h *.ih *.i *.ic *.asm *.def *.hpp *.yy *dsp *.dsw \ README INSTALL* LICENSE AUTHORS NEWS ChangeLog \ *.inc *.test *.result *.pem Moscow_leap des_key_file \ *.vcproj *.sln *.dat *.000001 *.require *.opt From e08ff11534c4ca13eea46590841fc38ec72b3462 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Jul 2006 12:10:12 +0300 Subject: [PATCH 02/42] Bug #16110: insert permitted into view col w/o default value When compiling INSERT statements the check whether columns are provided values depends on the flag whether a field is used in that query (Field::query_id). However the check for updatability of VIEW columns (check_view_insertability()) was calling fix_fields() and thus setting the Field::query_id even for the view fields that are not referenced in the current INSERT statement. So the correct check for columns without default values ( check_that_all_fields_are_given_values() ) is assuming that all the VIEW columns were mentioned in the INSERT field list and was issuing no warnings or errors. Fixed check_view_insertability() to turn off the flag whether or not to set Field::query_id (THREAD::set_query_id) before calling fix fields and restore it when it's done. mysql-test/r/view.result: Bug #16110: insert permitted into view col w/o default value * test case mysql-test/t/view.test: Bug #16110: insert permitted into view col w/o default value * test case sql/sql_insert.cc: Bug #16110: insert permitted into view col w/o default value * avoid setting the "field used" flag for fields when checking view columns for updatability. * a missing DBUG_RETURN added. --- mysql-test/r/view.result | 16 +++++++++++++++- mysql-test/t/view.test | 20 +++++++++++++++++++- sql/sql_insert.cc | 15 ++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 5bb407f4256..3cb89a995a1 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2735,4 +2735,18 @@ m e 4 a 1 b DROP VIEW v1; -DROP TABLE IF EXISTS t1,t2; +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT NOT NULL, b INT NULL DEFAULT NULL); +CREATE VIEW v1 AS SELECT a, b FROM t1; +INSERT INTO v1 (b) VALUES (2); +Warnings: +Warning 1423 Field of view 'test.v1' underlying table doesn't have a default value +SET SQL_MODE = STRICT_ALL_TABLES; +INSERT INTO v1 (b) VALUES (4); +ERROR HY000: Field of view 'test.v1' underlying table doesn't have a default value +SET SQL_MODE = ''; +SELECT * FROM t1; +a b +0 2 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index a1c1e9b2ad1..18ba85d3408 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2595,4 +2595,22 @@ CREATE TABLE t2 SELECT * FROM v1; SELECT * FROM t2; DROP VIEW v1; -DROP TABLE IF EXISTS t1,t2; +DROP TABLE t1,t2; + +# +# Bug#16110: insert permitted into view col w/o default value +# +CREATE TABLE t1 (a INT NOT NULL, b INT NULL DEFAULT NULL); +CREATE VIEW v1 AS SELECT a, b FROM t1; + +INSERT INTO v1 (b) VALUES (2); + +SET SQL_MODE = STRICT_ALL_TABLES; +--error 1423 +INSERT INTO v1 (b) VALUES (4); +SET SQL_MODE = ''; + +SELECT * FROM t1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8ffc6f53a43..26521fd65a6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -675,6 +675,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) uint used_fields_buff_size= (table->s->fields + 7) / 8; uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size); MY_BITMAP used_fields; + bool save_set_query_id= thd->set_query_id; DBUG_ENTER("check_key_in_view"); if (!used_fields_buff) @@ -687,15 +688,26 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) bitmap_clear_all(&used_fields); view->contain_auto_increment= 0; + /* + we must not set query_id for fields as they're not + really used in this context + */ + thd->set_query_id= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) - return TRUE; + { + thd->set_query_id= save_set_query_id; + DBUG_RETURN(TRUE); + } Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) + { + thd->set_query_id= save_set_query_id; DBUG_RETURN(TRUE); + } if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ @@ -705,6 +717,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) */ trans->item= field; } + thd->set_query_id= save_set_query_id; /* unique test */ for (trans= trans_start; trans != trans_end; trans++) { From 1401c2c71c5a99a6ac8e340138c5569fabd3f42e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Jul 2006 13:28:30 +0400 Subject: [PATCH 03/42] Better comments for void Item::top_level_item() --- sql/item.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sql/item.h b/sql/item.h index eca8ee184a1..3eab695cb5e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -275,9 +275,16 @@ public: Any new item which can be NULL must implement this call. */ virtual bool is_null() { return 0; } + /* - it is "top level" item of WHERE clause and we do not need correct NULL - handling + Inform the item that there will be no distinction between its result + being FALSE or NULL. + + NOTE + This function will be called for eg. Items that are top-level AND-parts + of the WHERE clause. Items implementing this function (currently + Item_cond_and and subquery-related item) enable special optimizations + when they are "top level". */ virtual void top_level_item() {} /* From 8e354677a81580fc7bd1ba4e3f6c7c426ed08c42 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Jul 2006 13:18:05 +0300 Subject: [PATCH 04/42] Bug #20569 Garbage in DECIMAL results from some mathematical functions Adding decimal "digits" in multiplication resulted in signed overflow and producing wrong results. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed by using large enough buffers and intermediary result types : dec2 (currently longlong) to hold result of adding decimal "digits" (currently int32). mysql-test/r/select.result: Bug #20569 Garbage in DECIMAL results from some mathematical functions * test suite for the bug mysql-test/t/select.test: Bug #20569 Garbage in DECIMAL results from some mathematical functions * test suite for the bug strings/decimal.c: Bug #20569 Garbage in DECIMAL results from some mathematical functions * fixed the overflow in adding decimal "digits" --- mysql-test/r/select.result | 3 +++ mysql-test/t/select.test | 5 +++++ strings/decimal.c | 13 ++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index e6c590489a0..7f01d453906 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3395,3 +3395,6 @@ a t1.b + 0 t1.c + 0 a t2.b + 0 c d 1 0 1 1 0 1 NULL 2 0 1 NULL NULL NULL NULL drop table t1,t2; +SELECT 0.9888889889 * 1.011111411911; +0.9888889889 * 1.011111411911 +0.9998769417899202067879 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index b75d0dd8bb6..b44f682c02e 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2901,3 +2901,8 @@ from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1 where t1.b <> 1 order by t1.a; drop table t1,t2; + +# +# Bug #20569: Garbage in DECIMAL results from some mathematical functions +# +SELECT 0.9888889889 * 1.011111411911; diff --git a/strings/decimal.c b/strings/decimal.c index 8786a513945..ecd92a54cc9 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -170,6 +170,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ #define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \ do \ { \ + DBUG_ASSERT((carry) <= 1); \ dec1 a=(from1)+(from2)+(carry); \ if (((carry)= a >= DIG_BASE)) /* no division here! */ \ a-=DIG_BASE; \ @@ -179,7 +180,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ #define ADD2(to, from1, from2, carry) \ do \ { \ - dec1 a=(from1)+(from2)+(carry); \ + dec2 a=((dec2)(from1))+(from2)+(carry); \ if (((carry)= a >= DIG_BASE)) \ a-=DIG_BASE; \ if (unlikely(a >= DIG_BASE)) \ @@ -187,7 +188,7 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ a-=DIG_BASE; \ carry++; \ } \ - (to)=a; \ + (to)=(dec1) a; \ } while(0) #define SUB(to, from1, from2, carry) /* to=from1-from2 */ \ @@ -1998,7 +1999,13 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) ADD2(*buf0, *buf0, lo, carry); carry+=hi; } - for (; carry; buf0--) + if (carry) + { + if (buf0 < to->buf) + return E_DEC_OVERFLOW; + ADD2(*buf0, *buf0, 0, carry); + } + for (buf0--; carry; buf0--) { if (buf0 < to->buf) return E_DEC_OVERFLOW; From cf7627bce09928d66129280b7903f6ab42fe2983 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Jul 2006 11:11:49 -0700 Subject: [PATCH 05/42] Fixed bug #18243. The implementation of the method Item_func_reverse::val_str for the REVERSE function modified the argument of the function. This led to wrong results for expressions that contained REVERSE(ref) if ref occurred somewhere else in the expressions. mysql-test/r/func_str.result: Added a test case for bug #18243. mysql-test/t/func_str.test: Added a test case for bug #18243. sql/item_strfunc.cc: Fixed bug #18243. The implementation of the method Item_func_reverse::val_str for the REVERSE function modified the argument of the function. This led to wrong results for expressions that contained REVERSE(ref) if ref occurred somewhere else in the expressions. The implementation of Item_func_reverse::val_str has been changed to make the argument intact. sql/item_strfunc.h: Fixed bug #18243. Added tmp_value to the Item_func_reverse class to store the result of the function. It erroneously replaced the argument before this fix. --- mysql-test/r/func_str.result | 15 ++++++++++++++ mysql-test/t/func_str.test | 17 ++++++++++++++++ sql/item_strfunc.cc | 39 +++++++++++++++++++----------------- sql/item_strfunc.h | 1 + 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 24e6bb6f38a..61a77c211d7 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1021,4 +1021,19 @@ select * from t1 where f1='test' and (f2= sha("TEST") or f2= sha("test")); f1 f2 test a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 drop table t1; +CREATE TABLE t1 (a varchar(10)); +INSERT INTO t1 VALUES ('abc'), ('xyz'); +SELECT a, CONCAT(a,' ',a) AS c FROM t1 +HAVING LEFT(c,LENGTH(c)-INSTR(REVERSE(c)," ")) = a; +a c +abc abc abc +xyz xyz xyz +SELECT a, CONCAT(a,' ',a) AS c FROM t1 +HAVING LEFT(CONCAT(a,' ',a), +LENGTH(CONCAT(a,' ',a))- +INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; +a c +abc abc abc +xyz xyz xyz +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index c36e15a08b9..9a1c75a8dc0 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -681,4 +681,21 @@ select * from t1 where f1='test' and (f2= sha("test") or f2= sha("TEST")); select * from t1 where f1='test' and (f2= sha("TEST") or f2= sha("test")); drop table t1; +# +# Bug#18243: REVERSE changes its argument +# + +CREATE TABLE t1 (a varchar(10)); +INSERT INTO t1 VALUES ('abc'), ('xyz'); + +SELECT a, CONCAT(a,' ',a) AS c FROM t1 + HAVING LEFT(c,LENGTH(c)-INSTR(REVERSE(c)," ")) = a; + +SELECT a, CONCAT(a,' ',a) AS c FROM t1 + HAVING LEFT(CONCAT(a,' ',a), + LENGTH(CONCAT(a,' ',a))- + INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; + +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ee585649f8c..7bc7956283b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -709,44 +709,47 @@ String *Item_func_reverse::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res = args[0]->val_str(str); - char *ptr,*end; + char *ptr, *end, *tmp; if ((null_value=args[0]->null_value)) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) return &my_empty_string; - res=copy_if_not_alloced(str,res,res->length()); - ptr = (char *) res->ptr(); - end=ptr+res->length(); + if (tmp_value.alloced_length() < res->length() && + tmp_value.realloc(res->length())) + { + null_value= 1; + return 0; + } + tmp_value.length(res->length()); + tmp_value.set_charset(res->charset()); + ptr= (char *) res->ptr(); + end= ptr + res->length(); + tmp= (char *) tmp_value.ptr() + tmp_value.length(); #ifdef USE_MB if (use_mb(res->charset())) { - String tmpstr; - tmpstr.copy(*res); - char *tmp = (char *) tmpstr.ptr() + tmpstr.length(); register uint32 l; while (ptr < end) { - if ((l=my_ismbchar(res->charset(), ptr,end))) - tmp-=l, memcpy(tmp,ptr,l), ptr+=l; + if ((l= my_ismbchar(res->charset(),ptr,end))) + { + tmp-= l; + memcpy(tmp,ptr,l); + ptr+= l; + } else - *--tmp=*ptr++; + *--tmp= *ptr++; } - memcpy((char *) res->ptr(),(char *) tmpstr.ptr(), res->length()); } else #endif /* USE_MB */ { - char tmp; while (ptr < end) - { - tmp=*ptr; - *ptr++=*--end; - *end=tmp; - } + *--tmp= *ptr++; } - return res; + return &tmp_value; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 89bab4a909c..f800c17182b 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -100,6 +100,7 @@ public: class Item_func_reverse :public Item_str_func { + String tmp_value; public: Item_func_reverse(Item *a) :Item_str_func(a) {} String *val_str(String *); From 41c7aece39b73635339ed8b50360d354858ce1fa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Jul 2006 14:41:01 -0700 Subject: [PATCH 06/42] Added a test case with views for bug 18243 (see also func_str.test). --- mysql-test/r/view.result | 13 +++++++++++++ mysql-test/t/view.test | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9486b9900f6..295f9442f13 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2750,3 +2750,16 @@ a b 0 2 DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (firstname text, surname text); +INSERT INTO t1 VALUES +("Bart","Simpson"),("Milhouse","van Houten"),("Montgomery","Burns"); +CREATE VIEW v1 AS SELECT CONCAT(firstname," ",surname) AS name FROM t1; +SELECT CONCAT(LEFT(name,LENGTH(name)-INSTR(REVERSE(name)," ")), +LEFT(name,LENGTH(name)-INSTR(REVERSE(name)," "))) AS f1 +FROM v1; +f1 +BartBart +Milhouse vanMilhouse van +MontgomeryMontgomery +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 18ba85d3408..623195dd527 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2614,3 +2614,19 @@ SELECT * FROM t1; DROP VIEW v1; DROP TABLE t1; + +# +# Bug #18243: expression over a view column that with the REVERSE function +# + +CREATE TABLE t1 (firstname text, surname text); +INSERT INTO t1 VALUES + ("Bart","Simpson"),("Milhouse","van Houten"),("Montgomery","Burns"); + +CREATE VIEW v1 AS SELECT CONCAT(firstname," ",surname) AS name FROM t1; +SELECT CONCAT(LEFT(name,LENGTH(name)-INSTR(REVERSE(name)," ")), + LEFT(name,LENGTH(name)-INSTR(REVERSE(name)," "))) AS f1 + FROM v1; + +DROP VIEW v1; +DROP TABLE t1; From a8fd83d676a5d8a64921f1f13ba4fa4f45221da8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Jul 2006 17:27:11 +0300 Subject: [PATCH 07/42] Bug #20569 Garbage in DECIMAL results from some mathematical functions * portability fix: moved the macro call after the C declaration strings/decimal.c: Bug #20569 Garbage in DECIMAL results from some mathematical functions * moved the macro call after the C declaration --- strings/decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/decimal.c b/strings/decimal.c index ecd92a54cc9..5a0bc0968b6 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -170,8 +170,8 @@ static const dec1 frac_max[DIG_PER_DEC1-1]={ #define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \ do \ { \ - DBUG_ASSERT((carry) <= 1); \ dec1 a=(from1)+(from2)+(carry); \ + DBUG_ASSERT((carry) <= 1); \ if (((carry)= a >= DIG_BASE)) /* no division here! */ \ a-=DIG_BASE; \ (to)=a; \ From 0806d9a86d73a1f1e089c9c3465c77ca82829b40 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 10 Jul 2006 16:27:03 +0300 Subject: [PATCH 08/42] BUG#14553: NULL in WHERE resets LAST_INSERT_ID To make MySQL compatible with some ODBC applications, you can find the AUTO_INCREMENT value for the last inserted row with the following query: SELECT * FROM tbl_name WHERE auto_col IS NULL. This is done with a special code that replaces 'auto_col IS NULL' with 'auto_col = LAST_INSERT_ID'. However this also resets the LAST_INSERT_ID to 0 as it uses it for a flag so as to ensure that only the first SELECT ... WHERE auto_col IS NULL after an INSERT has this special behaviour. In order to avoid resetting the LAST_INSERT_ID a special flag is introduced in the THD class. This flag is used to restrict the second and subsequent SELECTs instead of LAST_INSERT_ID. mysql-test/r/odbc.result: test suite for the bug mysql-test/r/rpl_insert_id.result: test for the fix in replication mysql-test/t/odbc.test: test suite for the bug mysql-test/t/rpl_insert_id.test: test for the fix in replication sql/sql_class.cc: initialize the flag sql/sql_class.h: flag's declaration and set code when setting the last_insert_id sql/sql_select.cc: the special flag is used instead of last_insert_id --- mysql-test/r/odbc.result | 11 +++++++++++ mysql-test/r/rpl_insert_id.result | 14 ++++++++++++++ mysql-test/t/odbc.test | 10 ++++++++++ mysql-test/t/rpl_insert_id.test | 20 +++++++++++++++++++- sql/sql_class.cc | 1 + sql/sql_class.h | 3 +++ sql/sql_select.cc | 4 ++-- 7 files changed, 60 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/odbc.result b/mysql-test/r/odbc.result index c0b2ada0053..30d839077f3 100644 --- a/mysql-test/r/odbc.result +++ b/mysql-test/r/odbc.result @@ -14,3 +14,14 @@ explain select * from t1 where b is null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables drop table t1; +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL); +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +a last_insert_id() +1 1 +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +a last_insert_id() +SELECT sql_no_cache a, last_insert_id() FROM t1; +a last_insert_id() +1 1 +DROP TABLE t1; diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index 8482f631553..e683ea2fb39 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -73,3 +73,17 @@ CREATE TABLE t1 ( a INT UNIQUE ); SET FOREIGN_KEY_CHECKS=0; INSERT INTO t1 VALUES (1),(1); ERROR 23000: Duplicate entry '1' for key 1 +drop table t1; +create table t1(a int auto_increment, key(a)); +create table t2(a int); +insert into t1 (a) values (null); +insert into t2 (a) select a from t1 where a is null; +insert into t2 (a) select a from t1 where a is null; +select * from t2; +a +1 +select * from t2; +a +1 +drop table t1; +drop table t2; diff --git a/mysql-test/t/odbc.test b/mysql-test/t/odbc.test index d4b6fc35e74..6a754bb32a7 100644 --- a/mysql-test/t/odbc.test +++ b/mysql-test/t/odbc.test @@ -21,4 +21,14 @@ select * from t1 where a is null; explain select * from t1 where b is null; drop table t1; +# +# Bug #14553: NULL in WHERE resets LAST_INSERT_ID +# +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL); +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +SELECT sql_no_cache a, last_insert_id() FROM t1 WHERE a IS NULL; +SELECT sql_no_cache a, last_insert_id() FROM t1; +DROP TABLE t1; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 49d3a03640c..766afad9e47 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -73,5 +73,23 @@ SET FOREIGN_KEY_CHECKS=0; --error 1062 INSERT INTO t1 VALUES (1),(1); sync_slave_with_master; - + +# +# Bug#14553: NULL in WHERE resets LAST_INSERT_ID +# +connection master; +drop table t1; +create table t1(a int auto_increment, key(a)); +create table t2(a int); +insert into t1 (a) values (null); +insert into t2 (a) select a from t1 where a is null; +insert into t2 (a) select a from t1 where a is null; +select * from t2; +sync_slave_with_master; +connection slave; +select * from t2; +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; # End of 4.1 tests diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d278ebe8dfa..0e51edd985b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -265,6 +265,7 @@ THD::THD() ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); } + substitute_null_with_insert_id = FALSE; } diff --git a/sql/sql_class.h b/sql/sql_class.h index d482a524934..006136a92f1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -893,6 +893,8 @@ public: bool last_cuted_field; bool no_errors, password, is_fatal_error; bool query_start_used,last_insert_id_used,insert_id_used,rand_used; + /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ + bool substitute_null_with_insert_id; bool time_zone_used; bool in_lock_tables; bool query_error, bootstrap, cleanup_done; @@ -988,6 +990,7 @@ public: { last_insert_id= id_arg; insert_id_used=1; + substitute_null_with_insert_id= TRUE; } inline ulonglong insert_id(void) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 57fb9738612..b6bd9c8b41b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4719,7 +4719,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) Field *field=((Item_field*) args[0])->field; if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null && (thd->options & OPTION_AUTO_IS_NULL) && - thd->insert_id()) + thd->insert_id() && thd->substitute_null_with_insert_id) { #ifdef HAVE_QUERY_CACHE query_cache_abort(&thd->net); @@ -4733,7 +4733,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond=new_cond; cond->fix_fields(thd, 0, &cond); } - thd->insert_id(0); // Clear for next request + thd->substitute_null_with_insert_id= FALSE; // Clear for next request } /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */ else if (((field->type() == FIELD_TYPE_DATE) || From fbd9103b7839854201b86ceff2cd1c2b5cedd623 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 10 Jul 2006 17:45:09 +0300 Subject: [PATCH 09/42] more 4.1->5.0 merge fixes for bug#14553 mysql-test/r/rpl_insert_id.result: more merge fixes for bug#14553 mysql-test/t/rpl_insert_id.test: more merge fixes for bug#14553 --- mysql-test/r/rpl_insert_id.result | 2 +- mysql-test/t/rpl_insert_id.test | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index 21eade8f9cf..20538c705a0 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -73,7 +73,7 @@ CREATE TABLE t1 ( a INT UNIQUE ); SET FOREIGN_KEY_CHECKS=0; INSERT INTO t1 VALUES (1),(1); ERROR 23000: Duplicate entry '1' for key 1 -drop table if exists t1, t2; +drop table t1; create table t1(a int auto_increment, key(a)); create table t2(a int); insert into t1 (a) values (null); diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 94ce7f95fb4..d2866bca60f 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -82,7 +82,6 @@ sync_slave_with_master; # Bug#14553: NULL in WHERE resets LAST_INSERT_ID # connection master; -drop table if exists t1,t2; create table t1(a int auto_increment, key(a)); create table t2(a int); insert into t1 (a) values (null); From ad88eabd35b34c557de1a4eede6c8fe9201dc01e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Jul 2006 00:34:37 +0400 Subject: [PATCH 10/42] Fixed bug#16302: Quantified subquery without any tables gives wrong results The ALL/ANY subqueries are the subject of MIN/MAX optimization. The matter of this optimization is to embed MIN() or MAX() function into the subquery in order to get only one row by which we can tell whether the expression with ALL/ANY subquery is true or false. But when it is applied to a subquery like 'select a_constant' the reported bug occurs. As no tables are specified in the subquery the do_select() function isn't called for the optimized subquery and thus no values have been added to a MIN()/MAX() function and it returns NULL instead of a_constant. This leads to a wrong query result. For the subquery like 'select a_constant' there is no reason to apply MIN/MAX optimization because the subquery anyway will return at most one row. Thus the Item_maxmin_subselect class is more appropriate for handling such subqueries. The Item_in_subselect::single_value_transformer() function now checks whether tables are specified for the subquery. If no then this subselect is handled like a UNION using an Item_maxmin_subselect object. mysql-test/t/subselect.test: Added test case for bug#16302: Quantified subquery without any tables gives wrong results mysql-test/r/subselect.result: Added test case for bug#16302: Quantified subquery without any tables gives wrong results sql/item_subselect.cc: Fixed bug#16302: Quantified subquery without any tables gives wrong results The Item_in_subselect::single_value_transformer() function now checks whether tables are specified for the subquery. If no then this subselect is handled like a UNION using an Item_maxmin_subselect object. --- mysql-test/r/subselect.result | 18 ++++++++++++++++++ mysql-test/t/subselect.test | 10 ++++++++++ sql/item_subselect.cc | 3 ++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 7925715a8b7..108f5dd1973 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2835,3 +2835,21 @@ a 4 DROP TABLE t1,t2,t3; purge master logs before (select adddate(current_timestamp(), interval -4 day)); +select 1 from dual where 1 < any (select 2); +1 +1 +select 1 from dual where 1 < all (select 2); +1 +1 +select 1 from dual where 2 > any (select 1); +1 +1 +select 1 from dual where 2 > all (select 1); +1 +1 +select 1 from dual where 1 < any (select 2 from dual); +1 +1 +select 1 from dual where 1 < all (select 2 from dual where 1!=1); +1 +1 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index cbc7a3afb5f..f7d5e7f8713 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1820,4 +1820,14 @@ DROP TABLE t1,t2,t3; purge master logs before (select adddate(current_timestamp(), interval -4 day)); + +# +# Bug#16302: Quantified subquery without any tables gives wrong results +# +select 1 from dual where 1 < any (select 2); +select 1 from dual where 1 < all (select 2); +select 1 from dual where 2 > any (select 1); +select 1 from dual where 2 > all (select 1); +select 1 from dual where 1 < any (select 2 from dual); +select 1 from dual where 1 < all (select 2 from dual where 1!=1); # End of 4.1 tests diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8241a8e0402..f6f8eec9af5 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -705,7 +705,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (!select_lex->group_list.elements && !select_lex->having && !select_lex->with_sum_func && - !(select_lex->next_select())) + !(select_lex->next_select()) && + select_lex->table_list.elements) { Item_sum_hybrid *item; if (func->l_op()) From d2bbf288a93ee50829e09d8faaf26dc0d6125476 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Jul 2006 01:52:18 +0400 Subject: [PATCH 11/42] Fixed bug#18503: Queries with a quantified subquery returning empty set may return a wrong result. An Item_sum_hybrid object has the was_values flag which indicates whether any values were added to the sum function. By default it is set to true and reset to false on any no_rows_in_result() call. This method is called only in return_zero_rows() function. An ALL/ANY subquery can be optimized by MIN/MAX optimization. The was_values flag is used to indicate whether the subquery has returned at least one row. This bug occurs because return_zero_rows() is called only when we know that the select will return zero rows before starting any scans but often such information is not known. In the reported case the return_zero_rows() function is not called and the was_values flag is not reset to false and yet the subquery return no rows Item_func_not_all and Item_func_nop_all functions return a wrong comparison result. The end_send_group() function now calls no_rows_in_result() for each item in the fields_list if there is no rows were found for the (sub)query. mysql-test/t/subselect.test: Added test case for bug#18503: Queries with a quantified subquery returning empty set may return a wrong result. mysql-test/r/subselect.result: Added test case for bug#18503: Queries with a quantified subquery returning empty set may return a wrong result. sql/sql_select.cc: Fixed bug#18503: Queries with a quantified subquery returning empty set may return a wrong result. The end_send_group() function now calls no_rows_in_result() for each item in the fields_list if there is no matching rows were found. --- mysql-test/r/subselect.result | 15 +++++++++++++++ mysql-test/t/subselect.test | 14 ++++++++++++++ sql/sql_select.cc | 5 +++++ 3 files changed, 34 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 7925715a8b7..2e2e28365d7 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2835,3 +2835,18 @@ a 4 DROP TABLE t1,t2,t3; purge master logs before (select adddate(current_timestamp(), interval -4 day)); +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f2 INT); +INSERT INTO t1 VALUES (1); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2); +f1 +1 +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE 1=0); +f1 +1 +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE f2=0); +f1 +1 +DROP TABLE t1, t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index cbc7a3afb5f..1012458a31b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1820,4 +1820,18 @@ DROP TABLE t1,t2,t3; purge master logs before (select adddate(current_timestamp(), interval -4 day)); + +# +# Bug#18503: Queries with a quantified subquery returning empty set may +# return a wrong result. +# +CREATE TABLE t1 (f1 INT); +CREATE TABLE t2 (f2 INT); +INSERT INTO t1 VALUES (1); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE 1=0); +INSERT INTO t2 VALUES (1); +INSERT INTO t2 VALUES (2); +SELECT * FROM t1 WHERE f1 > ALL (SELECT f2 FROM t2 WHERE f2=0); +DROP TABLE t1, t2; # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 709ff9726bb..8b3cfab8533 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6746,8 +6746,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (!join->first_record) { + List_iterator_fast it(*join->fields); + Item *item; /* No matching rows for group function */ join->clear(); + + while ((item= it++)) + item->no_rows_in_result(); } if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having From 414454300645a6238539d27174c1c5833972fe3a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Jul 2006 10:57:38 +0300 Subject: [PATCH 12/42] Bug #17212 results not sorted correctly by ORDER BY when using index * don't use join cache when the incoming data set is already ordered for ORDER BY This choice must be made because join cache will effectively reverse the join order and the results will be sorted by the index of the table that uses join cache. mysql-test/r/innodb_mysql.result: Bug #17212 results not sorted correctly by ORDER BY when using index * Test suite for the bug mysql-test/t/innodb_mysql.test: Bug #17212 results not sorted correctly by ORDER BY when using index * Test suite for the bug sql/sql_select.cc: Bug #17212 results not sorted correctly by ORDER BY when using index * don't use join cache when the incoming data set is already sorted --- mysql-test/r/innodb_mysql.result | 29 ++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 33 ++++++++++++++++++++++++++++++++ sql/sql_select.cc | 20 ++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 2a4e3555e3b..920d7aa42ce 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -54,3 +54,32 @@ c.c_id = 218 and expiredate is null; slai_id 12 drop table t1, t2; +CREATE TABLE t1 (a int, b int, KEY b (b)) Engine=InnoDB; +CREATE TABLE t2 (a int, b int, PRIMARY KEY (a,b)) Engine=InnoDB; +CREATE TABLE t3 (a int, b int, c int, PRIMARY KEY (a), +UNIQUE KEY b (b,c), KEY a (a,b,c)) Engine=InnoDB; +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 SELECT a + 1, b + 1 FROM t1; +INSERT INTO t1 SELECT a + 2, b + 2 FROM t1; +INSERT INTO t2 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); +INSERT INTO t2 SELECT a + 1, b FROM t2; +DELETE FROM t2 WHERE a = 1 AND b < 2; +INSERT INTO t3 VALUES (1,1,1),(2,1,2); +INSERT INTO t3 SELECT a + 2, a + 2, 3 FROM t3; +INSERT INTO t3 SELECT a + 4, a + 4, 3 FROM t3; +SELECT STRAIGHT_JOIN SQL_NO_CACHE t1.b, t1.a FROM t1, t3, t2 WHERE +t3.a = t2.a AND t2.b = t1.a AND t3.b = 1 AND t3.c IN (1, 2) +ORDER BY t1.b LIMIT 2; +b a +1 1 +2 2 +SELECT STRAIGHT_JOIN SQL_NO_CACHE t1.b, t1.a FROM t1, t3, t2 WHERE +t3.a = t2.a AND t2.b = t1.a AND t3.b = 1 AND t3.c IN (1, 2) +ORDER BY t1.b LIMIT 5; +b a +1 1 +2 2 +2 2 +3 3 +3 3 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index f31e4d64789..0b789e1a6d5 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -57,3 +57,36 @@ where c.c_id = 218 and expiredate is null; drop table t1, t2; + +# +# Bug#17212: results not sorted correctly by ORDER BY when using index +# (repeatable only w/innodb because of index props) +# +CREATE TABLE t1 (a int, b int, KEY b (b)) Engine=InnoDB; +CREATE TABLE t2 (a int, b int, PRIMARY KEY (a,b)) Engine=InnoDB; +CREATE TABLE t3 (a int, b int, c int, PRIMARY KEY (a), + UNIQUE KEY b (b,c), KEY a (a,b,c)) Engine=InnoDB; + +INSERT INTO t1 VALUES (1, 1); +INSERT INTO t1 SELECT a + 1, b + 1 FROM t1; +INSERT INTO t1 SELECT a + 2, b + 2 FROM t1; + +INSERT INTO t2 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); +INSERT INTO t2 SELECT a + 1, b FROM t2; +DELETE FROM t2 WHERE a = 1 AND b < 2; + +INSERT INTO t3 VALUES (1,1,1),(2,1,2); +INSERT INTO t3 SELECT a + 2, a + 2, 3 FROM t3; +INSERT INTO t3 SELECT a + 4, a + 4, 3 FROM t3; + +# demonstrate a problem when a must-use-sort table flag +# (sort_by_table=1) is being neglected. +SELECT STRAIGHT_JOIN SQL_NO_CACHE t1.b, t1.a FROM t1, t3, t2 WHERE + t3.a = t2.a AND t2.b = t1.a AND t3.b = 1 AND t3.c IN (1, 2) + ORDER BY t1.b LIMIT 2; + +# demonstrate the problem described in the bug report +SELECT STRAIGHT_JOIN SQL_NO_CACHE t1.b, t1.a FROM t1, t3, t2 WHERE + t3.a = t2.a AND t2.b = t1.a AND t3.b = 1 AND t3.c IN (1, 2) + ORDER BY t1.b LIMIT 5; +DROP TABLE t1, t2, t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 82c19255264..fd8a5149edd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3845,6 +3845,7 @@ make_join_readinfo(JOIN *join, uint options) { uint i; bool statistics= test(!(join->select_options & SELECT_DESCRIBE)); + bool ordered_set= 0; DBUG_ENTER("make_join_readinfo"); for (i=join->const_tables ; i < join->tables ; i++) @@ -3854,6 +3855,22 @@ make_join_readinfo(JOIN *join, uint options) tab->read_record.table= table; tab->read_record.file=table->file; tab->next_select=sub_select; /* normal select */ + + /* + Determine if the set is already ordered for ORDER BY, so it can + disable join cache because it will change the ordering of the results. + Code handles sort table that is at any location (not only first after + the const tables) despite the fact that it's currently prohibited. + */ + if (!ordered_set && + (table == join->sort_by_table && + (!join->order || join->skip_sort_order || + test_if_skip_sort_order(tab, join->order, join->select_limit, + 1)) + ) || + (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)) + ordered_set= 1; + switch (tab->type) { case JT_SYSTEM: // Only happens with left join table->status=STATUS_NO_RECORD; @@ -3924,10 +3941,11 @@ make_join_readinfo(JOIN *join, uint options) case JT_ALL: /* If previous table use cache + If the incoming data set is already sorted don't use cache. */ table->status=STATUS_NO_RECORD; if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && - tab->use_quick != 2 && !tab->on_expr) + tab->use_quick != 2 && !tab->on_expr && !ordered_set) { if ((options & SELECT_DESCRIBE) || !join_init_cache(join->thd,join->join_tab+join->const_tables, From 1e44259440f19d76c2422b64761530d57ec49a10 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Jul 2006 20:48:26 -0700 Subject: [PATCH 13/42] Fixed bug #19714. DESCRIBE returned the type BIGINT for a column of a view if the column was specified by an expression over values of the type INT. E.g. for the view defined as follows: CREATE VIEW v1 SELECT COALESCE(f1,f2) FROM t1 DESCRIBE returned type BIGINT for the only column of the view if f1,f2 are columns of the INT type. At the same time DESCRIBE returned type INT for the only column of the table defined by the statement: CREATE TABLE t2 SELECT COALESCE(f1,f2) FROM t1. This inconsistency was removed by the patch. Now the code chooses between INT/BIGINT depending on the precision of the aggregated column type. Thus both DESCRIBE commands above returns type INT for v1 and t2. mysql-test/r/analyse.result: Adjusted the results after having fixed bug #19714. mysql-test/r/bigint.result: Adjusted the results after having fixed bug #19714. mysql-test/r/create.result: Adjusted the results after having fixed bug #19714. mysql-test/r/olap.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_2myisam.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_3innodb.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_4heap.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_5merge.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_6bdb.result: Adjusted the results after having fixed bug #19714. mysql-test/r/ps_7ndb.result: Adjusted the results after having fixed bug #19714. mysql-test/r/sp.result: Adjusted the results after having fixed bug #19714. mysql-test/r/subselect.result: Adjusted the results after having fixed bug #19714. mysql-test/r/type_ranges.result: Adjusted the results after having fixed bug #19714. mysql-test/r/view.result: Added a test case for bug #19714. mysql-test/t/view.test: Added a test case for bug #19714. --- mysql-test/r/analyse.result | 24 ++++++++++++------------ mysql-test/r/bigint.result | 2 +- mysql-test/r/create.result | 4 ++-- mysql-test/r/olap.result | 4 ++-- mysql-test/r/ps_2myisam.result | 4 ++-- mysql-test/r/ps_3innodb.result | 4 ++-- mysql-test/r/ps_4heap.result | 4 ++-- mysql-test/r/ps_5merge.result | 8 ++++---- mysql-test/r/ps_6bdb.result | 4 ++-- mysql-test/r/ps_7ndb.result | 4 ++-- mysql-test/r/sp.result | 2 +- mysql-test/r/subselect.result | 12 ++++++------ mysql-test/r/type_ranges.result | 4 ++-- mysql-test/r/view.result | 11 +++++++++++ mysql-test/t/view.test | 13 +++++++++++++ sql/sql_select.cc | 9 +++++++-- 16 files changed, 71 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index f4e547dbc66..56f67cce4d6 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -39,10 +39,10 @@ t2 CREATE TABLE `t2` ( `Field_name` varbinary(255) NOT NULL default '', `Min_value` varbinary(255) default NULL, `Max_value` varbinary(255) default NULL, - `Min_length` bigint(11) NOT NULL default '0', - `Max_length` bigint(11) NOT NULL default '0', - `Empties_or_zeros` bigint(11) NOT NULL default '0', - `Nulls` bigint(11) NOT NULL default '0', + `Min_length` int(11) NOT NULL default '0', + `Max_length` int(11) NOT NULL default '0', + `Empties_or_zeros` int(11) NOT NULL default '0', + `Nulls` int(11) NOT NULL default '0', `Avg_value_or_avg_length` varbinary(255) NOT NULL default '', `Std` varbinary(255) default NULL, `Optimal_fieldtype` varbinary(64) NOT NULL default '' @@ -58,10 +58,10 @@ t2 CREATE TABLE `t2` ( `Field_name` varbinary(255) NOT NULL default '', `Min_value` varbinary(255) default NULL, `Max_value` varbinary(255) default NULL, - `Min_length` bigint(11) NOT NULL default '0', - `Max_length` bigint(11) NOT NULL default '0', - `Empties_or_zeros` bigint(11) NOT NULL default '0', - `Nulls` bigint(11) NOT NULL default '0', + `Min_length` int(11) NOT NULL default '0', + `Max_length` int(11) NOT NULL default '0', + `Empties_or_zeros` int(11) NOT NULL default '0', + `Nulls` int(11) NOT NULL default '0', `Avg_value_or_avg_length` varbinary(255) NOT NULL default '', `Std` varbinary(255) default NULL, `Optimal_fieldtype` varbinary(64) NOT NULL default '' @@ -81,10 +81,10 @@ t2 CREATE TABLE `t2` ( `Field_name` varbinary(255) NOT NULL default '', `Min_value` varbinary(255) default NULL, `Max_value` varbinary(255) default NULL, - `Min_length` bigint(11) NOT NULL default '0', - `Max_length` bigint(11) NOT NULL default '0', - `Empties_or_zeros` bigint(11) NOT NULL default '0', - `Nulls` bigint(11) NOT NULL default '0', + `Min_length` int(11) NOT NULL default '0', + `Max_length` int(11) NOT NULL default '0', + `Empties_or_zeros` int(11) NOT NULL default '0', + `Nulls` int(11) NOT NULL default '0', `Avg_value_or_avg_length` varbinary(255) NOT NULL default '', `Std` varbinary(255) default NULL, `Optimal_fieldtype` varbinary(64) NOT NULL default '' diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 3cdf4b17027..edc18319603 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -174,7 +174,7 @@ create table t1 select 1 as 'a'; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(1) NOT NULL default '0' + `a` int(1) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 select 9223372036854775809 as 'a'; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index c5b77ea4925..aa8c6d3d277 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -668,7 +668,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `b` int(11) NOT NULL, `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, - `c` bigint(1) NOT NULL default '0', + `c` int(1) NOT NULL default '0', PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -681,7 +681,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `b` int(11) default NULL, `a` varchar(12) character set utf8 collate utf8_bin NOT NULL, - `c` bigint(1) NOT NULL default '0', + `c` int(1) NOT NULL default '0', PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 225e306b3cf..28c1dc59540 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -620,8 +620,8 @@ CREATE VIEW v1 AS SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; DESC v1; Field Type Null Key Default Extra -a bigint(11) YES NULL -LENGTH(a) bigint(10) YES NULL +a int(11) YES 0 +LENGTH(a) int(10) YES NULL COUNT(*) bigint(21) NO 0 SELECT * FROM v1; a LENGTH(a) COUNT(*) diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 207d9ea7475..aa355067d1f 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1775,7 +1775,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1805,7 +1805,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 13aa549949c..ea7ed9371e8 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1758,7 +1758,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1788,7 +1788,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index a08dae945bd..fe4de89d6c7 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1759,7 +1759,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1789,7 +1789,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 6682b085097..bee7b2400b8 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1695,7 +1695,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1725,7 +1725,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 @@ -4709,7 +4709,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -4739,7 +4739,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index dc3b984949d..d352ec9f9e2 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1758,7 +1758,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1788,7 +1788,7 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 000a20da655..a72e6fb476a 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1758,7 +1758,7 @@ NULL as const12, @arg12 as param12, show create table t5 ; Table Create Table t5 CREATE TABLE `t5` ( - `const01` bigint(1) NOT NULL default '0', + `const01` int(1) NOT NULL default '0', `param01` bigint(20) default NULL, `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, @@ -1789,7 +1789,7 @@ t5 CREATE TABLE `t5` ( select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 -def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 +def test t5 t5 param01 param01 3 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 96bf2f01f86..50913fb1b90 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4921,7 +4921,7 @@ create table t3 as select * from v1| show create table t3| Table Create Table t3 CREATE TABLE `t3` ( - `j` bigint(11) default NULL + `j` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t3| j diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 981072139e0..11dc68fe99b 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1087,24 +1087,24 @@ CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT 1)) a; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(1) NOT NULL default '0', - `(SELECT 1)` bigint(1) NOT NULL default '0' + `a` int(1) NOT NULL default '0', + `(SELECT 1)` int(1) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a)) a; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(1) NOT NULL default '0', - `(SELECT a)` bigint(1) NOT NULL default '0' + `a` int(1) NOT NULL default '0', + `(SELECT a)` int(1) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 SELECT * FROM (SELECT 1 as a,(SELECT a+0)) a; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(1) NOT NULL default '0', - `(SELECT a+0)` bigint(3) NOT NULL default '0' + `a` int(1) NOT NULL default '0', + `(SELECT a+0)` int(3) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index bd89c09e94d..1310a5b71dd 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -273,7 +273,7 @@ create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, r show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment auto bigint(12) unsigned NULL NO PRI 0 # -t1 bigint(1) NULL NO 0 # +t1 int(1) NULL NO 0 # t2 varchar(1) latin1_swedish_ci NO # t3 varchar(256) latin1_swedish_ci NO # t4 varbinary(256) NULL NO # @@ -301,7 +301,7 @@ show full columns from t3; Field Type Collation Null Key Default Extra Privileges Comment c1 int(11) NULL YES NULL # c2 int(11) NULL YES NULL # -const bigint(1) NULL NO 0 # +const int(1) NULL NO 0 # drop table t1,t2,t3; create table t1 ( myfield INT NOT NULL, UNIQUE INDEX (myfield), unique (myfield), index(myfield)); drop table t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 295f9442f13..7d2ab63ca77 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2763,3 +2763,14 @@ Milhouse vanMilhouse van MontgomeryMontgomery DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (i int, j int); +CREATE VIEW v1 AS SELECT COALESCE(i,j) FROM t1; +DESCRIBE v1; +Field Type Null Key Default Extra +COALESCE(i,j) int(11) YES NULL +CREATE TABLE t2 SELECT COALESCE(i,j) FROM t1; +DESCRIBE t2; +Field Type Null Key Default Extra +COALESCE(i,j) int(11) YES NULL +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 623195dd527..88a4d489039 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2630,3 +2630,16 @@ SELECT CONCAT(LEFT(name,LENGTH(name)-INSTR(REVERSE(name)," ")), DROP VIEW v1; DROP TABLE t1; + +# +# Bug #19714: wrong type of a view column specified by an expressions over ints +# + +CREATE TABLE t1 (i int, j int); +CREATE VIEW v1 AS SELECT COALESCE(i,j) FROM t1; +DESCRIBE v1; +CREATE TABLE t2 SELECT COALESCE(i,j) FROM t1; +DESCRIBE t2; + +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 35a4f63aad1..2db62595a21 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8074,8 +8074,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, item->name, table, item->decimals); break; case INT_RESULT: - new_field=new Field_longlong(item->max_length, maybe_null, - item->name, table, item->unsigned_flag); + /* Select an integer type with the minimal fit precision */ + if (item->max_length > 11) + new_field=new Field_longlong(item->max_length, maybe_null, + item->name, table, item->unsigned_flag); + else + new_field=new Field_long(item->max_length, maybe_null, + item->name, table, item->unsigned_flag); break; case STRING_RESULT: DBUG_ASSERT(item->collation.collation); From 6c18e75caebb2945c3af92086298147e4156dd35 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Jul 2006 22:00:20 -0700 Subject: [PATCH 14/42] Correction for test tesults after pushing the fix for bug 19714. mysql-test/r/ps_7ndb.result: Correction for test results after pushing the fix for bug 19714. --- mysql-test/r/ps_7ndb.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index a72e6fb476a..8ce4c624fbc 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1788,8 +1788,8 @@ t5 CREATE TABLE `t5` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t5 t5 const01 const01 8 1 1 N 32769 0 63 -def test t5 t5 param01 param01 3 20 1 Y 32768 0 63 +def test t5 t5 const01 const01 3 1 1 N 32769 0 63 +def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 From 728fbb3ab564e850dd9214799d70663d3439aa6e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Jul 2006 12:09:36 +0300 Subject: [PATCH 15/42] fix for a compatibility build problem on MacOSX intel. Discussed with Kent. ndb/test/ndbapi/Makefile.am: Fix for a compatibility build problem on MacOSX Intel. --- ndb/test/ndbapi/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am index 19d3c4902a8..b639c71d07a 100644 --- a/ndb/test/ndbapi/Makefile.am +++ b/ndb/test/ndbapi/Makefile.am @@ -37,6 +37,10 @@ testBitfield \ DbCreate DbAsyncGenerator \ testSRBank +EXTRA_PROGRAMS = \ + test_event \ + test_event_merge \ + test_event_multi_table #flexTimedAsynch #testBlobs #flex_bench_mysql From 203d46bb387b4cb178fe0e4cf9135daa440233e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Jul 2006 19:28:58 -0700 Subject: [PATCH 16/42] Fixed bug #20519. The bug was due to a loss happened during a refactoring made on May 30 2005 that modified the function JOIN::reinit. As a result of it for any subquery the value of offset_limit_cnt was not restored for the following executions. Yet the first execution of the subquery made it equal to 0. The fix restores this value in the function JOIN::reinit. mysql-test/r/subselect.result: Added a test case fir bug #20519. mysql-test/t/subselect.test: Added a test case fir bug #20519. --- mysql-test/r/subselect.result | 45 +++++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 40 +++++++++++++++++++++++++++++++ sql/sql_select.cc | 5 ++++ 3 files changed, 90 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 11dc68fe99b..13f653b2f07 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3238,3 +3238,48 @@ i 10000000000000000000 DROP TABLE t1; DROP TABLE t2; +CREATE TABLE t1 ( +id bigint(20) unsigned NOT NULL auto_increment, +name varchar(255) NOT NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES +(1, 'Balazs'), (2, 'Joe'), (3, 'Frank'); +CREATE TABLE t2 ( +id bigint(20) unsigned NOT NULL auto_increment, +mid bigint(20) unsigned NOT NULL, +date date NOT NULL, +PRIMARY KEY (id) +); +INSERT INTO t2 VALUES +(1, 1, '2006-03-30'), (2, 2, '2006-04-06'), (3, 3, '2006-04-13'), +(4, 2, '2006-04-20'), (5, 1, '2006-05-01'); +SELECT *, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 0, 1) AS date_last, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 3, 1) AS date_next_to_last +FROM t1; +id name date_last date_next_to_last +1 Balazs 2006-05-01 NULL +2 Joe 2006-04-20 NULL +3 Frank 2006-04-13 NULL +SELECT *, +(SELECT COUNT(*) FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 1, 1) AS date_count +FROM t1; +id name date_count +1 Balazs NULL +2 Joe NULL +3 Frank NULL +SELECT *, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 0, 1) AS date_last, +(SELECT date FROM t2 WHERE mid = t1.id +ORDER BY date DESC LIMIT 1, 1) AS date_next_to_last +FROM t1; +id name date_last date_next_to_last +1 Balazs 2006-05-01 2006-03-30 +2 Joe 2006-04-20 2006-04-06 +3 Frank 2006-04-13 NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 9fc4f8a8d4e..310adcc5323 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2161,3 +2161,43 @@ SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); DROP TABLE t1; DROP TABLE t2; + +# +# Bug#20519: subselect with LIMIT M, N +# + +CREATE TABLE t1 ( + id bigint(20) unsigned NOT NULL auto_increment, + name varchar(255) NOT NULL, + PRIMARY KEY (id) +); +INSERT INTO t1 VALUES + (1, 'Balazs'), (2, 'Joe'), (3, 'Frank'); + +CREATE TABLE t2 ( + id bigint(20) unsigned NOT NULL auto_increment, + mid bigint(20) unsigned NOT NULL, + date date NOT NULL, + PRIMARY KEY (id) +); +INSERT INTO t2 VALUES + (1, 1, '2006-03-30'), (2, 2, '2006-04-06'), (3, 3, '2006-04-13'), + (4, 2, '2006-04-20'), (5, 1, '2006-05-01'); + +SELECT *, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 0, 1) AS date_last, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 3, 1) AS date_next_to_last + FROM t1; +SELECT *, + (SELECT COUNT(*) FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 1, 1) AS date_count + FROM t1; +SELECT *, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 0, 1) AS date_last, + (SELECT date FROM t2 WHERE mid = t1.id + ORDER BY date DESC LIMIT 1, 1) AS date_next_to_last + FROM t1; +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8361986e020..a7158960ed0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1209,6 +1209,11 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); + + unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ? + select_lex->offset_limit->val_uint() : + ULL(0)); + first_record= 0; if (exec_tmp_table1) From 109615048dfd24859b1095cc40d0a948c6559474 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 15 Jul 2006 00:28:21 -0700 Subject: [PATCH 17/42] Fixed bug #20869. The bug caused a crash of the server if a subquery with ORDER BY DESC used the range access method. The bug happened because the method QUICK_SELECT_DESC::reset was not reworked after MRR interface had been introduced. mysql-test/r/subselect.result: Added a test case for bug #20869. mysql-test/t/subselect.test: Added a test case for bug #20869. --- mysql-test/r/subselect.result | 36 +++++++++++++++++++++++++++++++++ mysql-test/t/subselect.test | 38 +++++++++++++++++++++++++++++++++++ sql/opt_range.h | 2 +- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 11dc68fe99b..5bd02c9ea6c 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3238,3 +3238,39 @@ i 10000000000000000000 DROP TABLE t1; DROP TABLE t2; +CREATE TABLE t1 ( +i1 int(11) NOT NULL default '0', +i2 int(11) NOT NULL default '0', +t datetime NOT NULL default '0000-00-00 00:00:00', +PRIMARY KEY (i1,i2,t) +); +INSERT INTO t1 VALUES +(24,1,'2005-03-03 16:31:31'),(24,1,'2005-05-27 12:40:07'), +(24,1,'2005-05-27 12:40:08'),(24,1,'2005-05-27 12:40:10'), +(24,1,'2005-05-27 12:40:25'),(24,1,'2005-05-27 12:40:30'), +(24,2,'2005-03-03 13:43:05'),(24,2,'2005-03-03 16:23:31'), +(24,2,'2005-03-03 16:31:30'),(24,2,'2005-05-27 12:37:02'), +(24,2,'2005-05-27 12:40:06'); +CREATE TABLE t2 ( +i1 int(11) NOT NULL default '0', +i2 int(11) NOT NULL default '0', +t datetime default NULL, +PRIMARY KEY (i1) +); +INSERT INTO t2 VALUES (24,1,'2006-06-20 12:29:40'); +EXPLAIN +SELECT * FROM t1,t2 +WHERE t1.t = (SELECT t1.t FROM t1 +WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 +ORDER BY t1.t DESC LIMIT 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 system NULL NULL NULL NULL 1 +1 PRIMARY t1 index NULL PRIMARY 16 NULL 11 Using where; Using index +2 DEPENDENT SUBQUERY t1 range PRIMARY PRIMARY 16 NULL 5 Using where; Using index +SELECT * FROM t1,t2 +WHERE t1.t = (SELECT t1.t FROM t1 +WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 +ORDER BY t1.t DESC LIMIT 1); +i1 i2 t i1 i2 t +24 1 2005-05-27 12:40:30 24 1 2006-06-20 12:29:40 +DROP TABLE t1, t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 9fc4f8a8d4e..4a977dd4826 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2161,3 +2161,41 @@ SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); DROP TABLE t1; DROP TABLE t2; + +# +# Bug#20869: subselect with range access by DESC +# + +CREATE TABLE t1 ( + i1 int(11) NOT NULL default '0', + i2 int(11) NOT NULL default '0', + t datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (i1,i2,t) +); +INSERT INTO t1 VALUES +(24,1,'2005-03-03 16:31:31'),(24,1,'2005-05-27 12:40:07'), +(24,1,'2005-05-27 12:40:08'),(24,1,'2005-05-27 12:40:10'), +(24,1,'2005-05-27 12:40:25'),(24,1,'2005-05-27 12:40:30'), +(24,2,'2005-03-03 13:43:05'),(24,2,'2005-03-03 16:23:31'), +(24,2,'2005-03-03 16:31:30'),(24,2,'2005-05-27 12:37:02'), +(24,2,'2005-05-27 12:40:06'); + +CREATE TABLE t2 ( + i1 int(11) NOT NULL default '0', + i2 int(11) NOT NULL default '0', + t datetime default NULL, + PRIMARY KEY (i1) +); +INSERT INTO t2 VALUES (24,1,'2006-06-20 12:29:40'); + +EXPLAIN +SELECT * FROM t1,t2 + WHERE t1.t = (SELECT t1.t FROM t1 + WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 + ORDER BY t1.t DESC LIMIT 1); +SELECT * FROM t1,t2 + WHERE t1.t = (SELECT t1.t FROM t1 + WHERE t1.t < t2.t AND t1.i2=1 AND t2.i1=t1.i1 + ORDER BY t1.t DESC LIMIT 1); + +DROP TABLE t1, t2; diff --git a/sql/opt_range.h b/sql/opt_range.h index cdb00ea7d0c..9474f2d469f 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -668,7 +668,7 @@ private: #ifdef NOT_USED bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); #endif - int reset(void) { next=0; rev_it.rewind(); return 0; } + int reset(void) { rev_it.rewind(); return QUICK_RANGE_SELECT::reset(); } List rev_ranges; List_iterator rev_it; }; From 1c96f2d73eabc9217a2ad04ad232b0650eab2277 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Jul 2006 00:45:38 +0400 Subject: [PATCH 18/42] Fixed bug#10977: No warning issued if a column name is truncated When an alias is set to a column leading spaces are removed from the alias. But when this is done on aliases set by user this can lead to confusion. Now Item::set_name() method issues the warning if leading spaces were removed from an alias set by user. New warning message is added. mysql-test/t/select.test: Added test case for bug#10977:No warning issued if a column name is truncated. mysql-test/r/select.result: Added test case for bug#10977:No warning issued if a column name is truncated. sql/sql_yacc.yy: Fixed bug#10977: No warning issued if a column name is truncated The is_autogenerated_name flag is set before set_name() method call. sql/item.cc: Fixed bug#10977: No warning issued if a column name is truncated Now Item::set_name() method issues the warning if leading spaces were removed from an alias set by user. --- mysql-test/r/select.result | 5 +++++ mysql-test/t/select.test | 5 +++++ sql/item.cc | 6 ++++++ sql/sql_yacc.yy | 4 ++-- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 7f01d453906..30708c0ccda 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3398,3 +3398,8 @@ drop table t1,t2; SELECT 0.9888889889 * 1.011111411911; 0.9888889889 * 1.011111411911 0.9998769417899202067879 +select 1 as ' a '; +a +1 +Warnings: +Warning 1466 Leading spaces are removed from name ' a ' diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index b44f682c02e..ac5c121550a 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2906,3 +2906,8 @@ drop table t1,t2; # Bug #20569: Garbage in DECIMAL results from some mathematical functions # SELECT 0.9888889889 * 1.011111411911; + +# +# Bug #10977: No warning issued if a column name is truncated +# +select 1 as ' a '; diff --git a/sql/item.cc b/sql/item.cc index 511ea1ffb44..ad8b79182d4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -573,6 +573,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) } if (cs->ctype) { + uint orig_len= length; /* This will probably need a better implementation in the future: a function in CHARSET_INFO structure. @@ -582,6 +583,11 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) length--; str++; } + if (orig_len != length && !is_autogenerated_name) + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES), + str + length - orig_len); + } if (!my_charset_same(cs, system_charset_info)) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index deac9cb5c40..425945f525e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4060,8 +4060,8 @@ select_item: YYABORT; if ($4.str) { - $2->set_name($4.str, $4.length, system_charset_info); $2->is_autogenerated_name= FALSE; + $2->set_name($4.str, $4.length, system_charset_info); } else if (!$2->name) { char *str = $1; @@ -4936,8 +4936,8 @@ udf_expr: { if ($4.str) { - $2->set_name($4.str, $4.length, system_charset_info); $2->is_autogenerated_name= FALSE; + $2->set_name($4.str, $4.length, system_charset_info); } else $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); From 84245d4e87174ef4dbd4fdb2d5d1e7f4198642a9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Jul 2006 01:18:08 +0400 Subject: [PATCH 19/42] errmsg.txt: Fixed bug#10977: No warning issued if a column name is truncated New warning message is added. sql/share/errmsg.txt: Fixed bug#10977: No warning issued if a column name is truncated New warning message is added. --- sql/share/errmsg.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9b20c37ece2..5c967ba19bd 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5621,3 +5621,5 @@ ER_TABLE_CANT_HANDLE_SPKEYS eng "The used table type doesn't support SPATIAL indexes" ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA eng "Triggers can not be created on system tables" +ER_REMOVED_SPACES + eng "Leading spaces are removed from name '%s'" From 9a5daa602a11a2285b69b3c400d2e683cf63837a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Jul 2006 14:22:21 +0400 Subject: [PATCH 20/42] mysql.test, mysql.result: Corrected the test case after fixing bug#10977 mysql-test/t/mysql.test: Corrected the test case after fixing bug#10977 mysql-test/r/mysql.result: Corrected the test case after fixing bug#10977 --- mysql-test/r/mysql.result | 8 ++++---- mysql-test/t/mysql.test | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 4b7084e813c..d70366a7589 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -36,19 +36,19 @@ Tables_in_test t1 t2 t3 - +_ Test delimiter : from command line a 1 - +_ Test delimiter :; from command line a 1 - +_ Test 'go' command(vertical output) G *************************** 1. row *************************** a: 1 - +_ Test 'go' command g a 1 diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index ac4c323f51e..98fadcfc75d 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -20,16 +20,16 @@ insert into t1 values(1); --disable_query_log # Test delimiter : supplied on the command line -select "Test delimiter : from command line" as " "; +select "Test delimiter : from command line" as "_"; --exec $MYSQL test --delimiter=":" -e "select * from t1:" # Test delimiter :; supplied on the command line -select "Test delimiter :; from command line" as " "; +select "Test delimiter :; from command line" as "_"; --exec $MYSQL test --delimiter=":;" -e "select * from t1:;" # Test 'go' command (vertical output) \G -select "Test 'go' command(vertical output) \G" as " "; +select "Test 'go' command(vertical output) \G" as "_"; --exec $MYSQL test -e "select * from t1\G" # Test 'go' command \g -select "Test 'go' command \g" as " "; +select "Test 'go' command \g" as "_"; --exec $MYSQL test -e "select * from t1\g" --enable_query_log drop table t1; From 14d72663f1eb0d9ec7cf7d353f09c2cc14a30597 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Jul 2006 16:12:42 +0400 Subject: [PATCH 21/42] select.result, select.test: Test case for bug#10977 altered to make it work in both plain and ps-protocol modes. mysql-test/t/select.test: Test case for bug#10977 altered to make it work in both plain and ps-protocol modes. mysql-test/r/select.result: Test case for bug#10977 altered to make it work in both plain and ps-protocol modes. --- mysql-test/r/select.result | 7 ++++--- mysql-test/t/select.test | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 30708c0ccda..c2218585f7c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3398,8 +3398,9 @@ drop table t1,t2; SELECT 0.9888889889 * 1.011111411911; 0.9888889889 * 1.011111411911 0.9998769417899202067879 -select 1 as ' a '; -a -1 +prepare stmt from 'select 1 as " a "'; Warnings: Warning 1466 Leading spaces are removed from name ' a ' +execute stmt; +a +1 diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index ac5c121550a..592e366f835 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2910,4 +2910,5 @@ SELECT 0.9888889889 * 1.011111411911; # # Bug #10977: No warning issued if a column name is truncated # -select 1 as ' a '; +prepare stmt from 'select 1 as " a "'; +execute stmt; From c3f0d2f6cba13bc7f7f56ba1233682ef4c3f3593 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Jul 2006 15:28:24 -0700 Subject: [PATCH 22/42] Post-merge fix. --- mysql-test/r/subselect.result | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 3ce8124ade9..ae929cf9c2e 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3283,6 +3283,7 @@ id name date_last date_next_to_last 2 Joe 2006-04-20 2006-04-06 3 Frank 2006-04-13 NULL DROP TABLE t1,t2; +CREATE TABLE t1 ( i1 int(11) NOT NULL default '0', i2 int(11) NOT NULL default '0', t datetime NOT NULL default '0000-00-00 00:00:00', From 6ec7976df97d5c9ced3f2e50339c74f19cda32fd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Jul 2006 12:36:55 -0700 Subject: [PATCH 23/42] Fixed bug #17526: incorrect print method for class Item_func_trim. For 4.1 it caused wrong output for EXPLAIN EXTENDED commands if expressions with the TRIM function of two arguments were used. For 5.0 it caused an error message when trying to select from a view with the TRIM function of two arguments. This unexpected error message was due to the fact that the print method for the class Item_func_trim was inherited from the class Item_func. Yet the TRIM function does not take a list of its arguments. Rather it takes the arguments in the form: [{BOTH | LEADING | TRAILING} [remstr] FROM] str) | [remstr FROM] str mysql-test/r/func_str.result: Added a test case for bug #17526: uncorrect print method for class Item_func_trim. mysql-test/t/func_str.test: Added a test case for bug #17526: incorrect print method for class Item_func_trim. sql/item_strfunc.cc: Fixed bug #17526: incorrect print method for class Item_func_trim. Added an implementation for the virtual function print in the class Item_func_trim. The implementation takes into account the fact the TRIM function takes the arguments in the following forms: [{BOTH | LEADING | TRAILING} [remstr] FROM] str) | [remstr FROM] str sql/item_strfunc.h: Fixed bug #17526: incorrect print method for class Item_func_trim. Added an implementation for the virtual function print in the class Item_func_trim. Declared a virtual method to return the mode of the TRIM function: LEADING, TRAILING or BOTH. Added implementations of this method for Item_func_trim and its descendants Item_func_ltrim and Item_func_rtrim. --- mysql-test/r/func_str.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 15 +++++++++++++++ sql/item_strfunc.cc | 17 +++++++++++++++++ sql/item_strfunc.h | 4 ++++ 4 files changed, 64 insertions(+) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 61a77c211d7..2c15e5581e8 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1036,4 +1036,32 @@ a c abc abc abc xyz xyz xyz DROP TABLE t1; +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(leading _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(trailing _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9a1c75a8dc0..3c855a32eed 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -697,5 +697,20 @@ SELECT a, CONCAT(a,' ',a) AS c FROM t1 INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; DROP TABLE t1; + +# +# Bug#17526: WRONG PRINT for TRIM FUNCTION with two arguments +# + +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); + +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; + +DROP TABLE t1; --echo End of 4.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7bc7956283b..1c5b947cb2b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1444,6 +1444,23 @@ void Item_func_trim::fix_length_and_dec() } } +void Item_func_trim::print(String *str) +{ + if (arg_count == 1) + { + Item_func::print(str); + return; + } + str->append(Item_func_trim::func_name()); + str->append('('); + str->append(mode_name()); + str->append(' '); + args[1]->print(str); + str->append(" from ",6); + args[0]->print(str); + str->append(')'); +} + /* Item_func_password */ diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index f800c17182b..880a19242ca 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -218,6 +218,8 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "trim"; } + void print(String *str); + virtual const char *mode_name() const { return "both"; } }; @@ -228,6 +230,7 @@ public: Item_func_ltrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "ltrim"; } + const char *mode_name() const { return "leading"; } }; @@ -238,6 +241,7 @@ public: Item_func_rtrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "rtrim"; } + const char *mode_name() const { return "trailing"; } }; From f8dda7bfb928c0eaee550db57f5288e0575ea378 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Jul 2006 16:42:19 -0700 Subject: [PATCH 24/42] Added a test case with views for bug #17526. mysql-test/r/func_str.result: Adjusted results for the test case of bug 17526. sql/item_strfunc.cc: Post-merge modification --- mysql-test/r/func_str.result | 10 +++++----- mysql-test/r/view.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 24 ++++++++++++++++++++++++ sql/item_strfunc.cc | 2 +- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index ae62010f118..a857f5055a2 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1059,27 +1059,27 @@ EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(`test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(leading _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(leading _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(trailing _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(trailing _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') DROP TABLE t1; End of 4.1 tests create table t1 (d decimal default null); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 7d2ab63ca77..c8a673e2209 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2774,3 +2774,36 @@ Field Type Null Key Default Extra COALESCE(i,j) int(11) YES NULL DROP VIEW v1; DROP TABLE t1,t2; +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yady'); +SELECT TRIM(BOTH 'y' FROM s) FROM t1; +TRIM(BOTH 'y' FROM s) +adda +ad +CREATE VIEW v1 AS SELECT TRIM(BOTH 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(BOTH 'y' FROM s) +adda +ad +DROP VIEW v1; +SELECT TRIM(LEADING 'y' FROM s) FROM t1; +TRIM(LEADING 'y' FROM s) +adda +ady +CREATE VIEW v1 AS SELECT TRIM(LEADING 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(LEADING 'y' FROM s) +adda +ady +DROP VIEW v1; +SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +TRIM(TRAILING 'y' FROM s) +yadda +yad +CREATE VIEW v1 AS SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(TRAILING 'y' FROM s) +yadda +yad +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 88a4d489039..6399cef9086 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2643,3 +2643,27 @@ DESCRIBE t2; DROP VIEW v1; DROP TABLE t1,t2; + +# +# Bug #17526: views with TRIM functions +# + +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yady'); + +SELECT TRIM(BOTH 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(BOTH 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +SELECT TRIM(LEADING 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(LEADING 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +DROP TABLE t1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7289c17f996..58ddb331b2e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1515,7 +1515,7 @@ void Item_func_trim::print(String *str) str->append(mode_name()); str->append(' '); args[1]->print(str); - str->append(" from ",6); + str->append(STRING_WITH_LEN(" from ")); args[0]->print(str); str->append(')'); } From 68698c04abfbcbee1b67b5daca6695ada679ac4f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 03:04:04 +0400 Subject: [PATCH 25/42] BUG#20975: Incorrect query result for NOT (subquery): Add implementations of Item_func_{nop,not}_all::neg_transformer mysql-test/r/subselect.result: BUG#20975: testcase mysql-test/t/subselect.test: BUG#20975: testcase sql/mysql_priv.h: Make chooser_compare_func_creator visible in item.h --- mysql-test/r/subselect.result | 26 ++++++++++++++++++++++++++ mysql-test/t/subselect.test | 16 ++++++++++++++++ sql/item_cmpfunc.cc | 22 ++++++++++++++++++++++ sql/item_cmpfunc.h | 2 ++ sql/item_subselect.cc | 6 +++--- sql/item_subselect.h | 9 ++++----- sql/mysql_priv.h | 3 ++- sql/sql_parse.cc | 2 +- 8 files changed, 76 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c78f0951469..595d80f1218 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2868,3 +2868,29 @@ select 1 from dual where 1 < any (select 2 from dual); select 1 from dual where 1 < all (select 2 from dual where 1!=1); 1 1 +create table t1 (s1 char); +insert into t1 values (1),(2); +select * from t1 where (s1 < any (select s1 from t1)); +s1 +1 +select * from t1 where not (s1 < any (select s1 from t1)); +s1 +2 +select * from t1 where (s1 < ALL (select s1+1 from t1)); +s1 +1 +select * from t1 where not(s1 < ALL (select s1+1 from t1)); +s1 +2 +select * from t1 where (s1+1 = ANY (select s1 from t1)); +s1 +1 +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); +s1 +2 +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +s1 +1 +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +s1 +2 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e01310bba45..1bcd37dd7d7 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1844,4 +1844,20 @@ select 1 from dual where 2 > any (select 1); select 1 from dual where 2 > all (select 1); select 1 from dual where 1 < any (select 2 from dual); select 1 from dual where 1 < all (select 2 from dual where 1!=1); + +# BUG#20975 Wrong query results for subqueries within NOT +create table t1 (s1 char); +insert into t1 values (1),(2); + +select * from t1 where (s1 < any (select s1 from t1)); +select * from t1 where not (s1 < any (select s1 from t1)); + +select * from t1 where (s1 < ALL (select s1+1 from t1)); +select * from t1 where not(s1 < ALL (select s1+1 from t1)); + +select * from t1 where (s1+1 = ANY (select s1 from t1)); +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); + +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f14efc7187b..a32bd0a7337 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3099,6 +3099,28 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ } +Item *Item_func_nop_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ANY (SELECT ...)) -> e $rev_cmp$" ALL (SELECT ...) */ + Item_func_not_all *new_item= new Item_func_not_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->func= allany->func_creator(FALSE); + allany->all= !allany->all; + allany->upper_item= new_item; + return new_item; +} + +Item *Item_func_not_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ALL (SELECT ...)) -> e $rev_cmp$" ANY (SELECT ...) */ + Item_func_nop_all *new_item= new Item_func_nop_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->all= !allany->all; + allany->func= allany->func_creator(TRUE); + allany->upper_item= new_item; + return new_item; +} + Item *Item_func_eq::negated_item() /* a = b -> a != b */ { return new Item_func_ne(args[0], args[1]); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 73abe208d9e..0e157fd412c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -268,6 +268,7 @@ public: void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; }; bool empty_underlying_subquery(); + Item *neg_transformer(THD *thd); }; @@ -278,6 +279,7 @@ public: Item_func_nop_all(Item *a) :Item_func_not_all(a) {} longlong val_int(); const char *func_name() const { return ""; } + Item *neg_transformer(THD *thd); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f6f8eec9af5..c95a91de13e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -542,14 +542,14 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, } Item_allany_subselect::Item_allany_subselect(Item * left_exp, - Comp_creator *fn, + chooser_compare_func_creator fc, st_select_lex *select_lex, bool all_arg) - :Item_in_subselect(), all(all_arg) + :Item_in_subselect(), all(all_arg), func_creator(fc) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; - func= fn; + func= func_creator(all_arg); init(select_lex, new select_exists_subselect(this)); max_columns= 1; abort_on_null= 0; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index dec32398a80..93171ad64a1 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -251,14 +251,13 @@ public: /* ALL/ANY/SOME subselect */ class Item_allany_subselect :public Item_in_subselect { -protected: - Comp_creator *func; - public: + chooser_compare_func_creator func_creator; + Comp_creator *func; bool all; - Item_allany_subselect(Item * left_expr, Comp_creator *f, - st_select_lex *select_lex, bool all); + Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc, + st_select_lex *select_lex, bool all); // only ALL subquery has upper not subs_type substype() { return all?ALL_SUBS:ANY_SUBS; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d231942bb7a..d03c6acac7c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -387,8 +387,9 @@ enum enum_var_type OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL }; class sys_var; -#include "item.h" +class Comp_creator; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); +#include "item.h" /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fbe36bfdc4a..660c77e81e4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5436,7 +5436,7 @@ Item * all_any_subquery_creator(Item *left_expr, return new Item_func_not(new Item_in_subselect(left_expr, select_lex)); Item_allany_subselect *it= - new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all); + new Item_allany_subselect(left_expr, cmp, select_lex, all); if (all) return it->upper_item= new Item_func_not_all(it); /* ALL */ From 4e59d30dc9ef76c79c8e8c92bfad9b394d4d5c9b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 11:59:46 +0300 Subject: [PATCH 26/42] Fix for BUG#21007. The problem was that store_top_level_join_columns() incorrectly assumed that the left/right neighbor of a nested join table reference can be only at the same level in the join tree. The fix checks if the current nested join table reference has no immediate left/right neighbor, and if so chooses the left/right neighbors of the nearest upper level, where these references are != NULL. mysql-test/r/group_min_max.result: Test for BUG#21007. mysql-test/t/group_min_max.test: Test for BUG#21007. sql/sql_base.cc: After computing and materializing the columns of all NATURAL joins in a FROM clause, the procedure store_top_level_join_columns() has to change the current natural join into a leaf table reference for name resolution. For this it needs to make the left neighbor point to the natural join table reference, and the natural join itself point to its left neighbor. This fix correctly determines the left/right neighbors of a table reference, even if the neghbors are at higher levels in the nested join tree. The rule is that if a table reference has no immediate left/right neighbors, we recursively pick the left/right neighbor of the level(s) above. --- mysql-test/r/group_min_max.result | 43 +++++++++++++++++++++++++++ mysql-test/t/group_min_max.test | 48 +++++++++++++++++++++++++++++++ sql/sql_base.cc | 38 +++++++++++++++--------- 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index d62586dba85..fe6f7c4ca55 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2099,3 +2099,46 @@ SOUTH EAST SOUTH EAST SOUTH WEST SOUTH WEST WESTERN WESTERN DROP TABLE t1; +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); +SELECT * FROM +t1 +NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id3 id5 id4 id3 id6 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +t1 +NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id4 id3 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); +id2 id1 id3 id4 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +DROP TABLE t1,t2,t3,t4,t5,t6; diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 874f3cd1a80..5427727a8f4 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -746,3 +746,51 @@ EXPLAIN SELECT DISTINCT a,a FROM t1 ORDER BY a; SELECT DISTINCT a,a FROM t1 ORDER BY a; DROP TABLE t1; + +# +# Bug #21007: NATURAL JOIN (any JOIN (2 x NATURAL JOIN)) crashes the server +# + +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); + +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); + +-- original bug query +SELECT * FROM +t1 + NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +-- inner join swapped +SELECT * FROM +t1 + NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +-- one join less, no ON cond +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); + +-- wrong error message: 'id2' - ambiguous column +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) + NATURAL JOIN +t1; +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) + NATURAL JOIN +t1; + +DROP TABLE t1,t2,t3,t4,t5,t6; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5383bb52aaa..7f9076bb46e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4041,36 +4041,48 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (table_ref->nested_join) { List_iterator_fast nested_it(table_ref->nested_join->join_list); - TABLE_LIST *cur_left_neighbor= nested_it++; - TABLE_LIST *cur_right_neighbor= NULL; + TABLE_LIST *same_level_left_neighbor= nested_it++; + TABLE_LIST *same_level_right_neighbor= NULL; + /* Left/right-most neighbors, possibly at higher levels in the join tree. */ + TABLE_LIST *real_left_neighbor, *real_right_neighbor; - while (cur_left_neighbor) + while (same_level_left_neighbor) { - TABLE_LIST *cur_table_ref= cur_left_neighbor; - cur_left_neighbor= nested_it++; + TABLE_LIST *cur_table_ref= same_level_left_neighbor; + same_level_left_neighbor= nested_it++; /* The order of RIGHT JOIN operands is reversed in 'join list' to transform it into a LEFT JOIN. However, in this procedure we need the join operands in their lexical order, so below we reverse the - join operands. Notice that this happens only in the first loop, and - not in the second one, as in the second loop cur_left_neighbor == NULL. - This is the correct behavior, because the second loop - sets cur_table_ref reference correctly after the join operands are + join operands. Notice that this happens only in the first loop, + and not in the second one, as in the second loop + same_level_left_neighbor == NULL. + This is the correct behavior, because the second loop sets + cur_table_ref reference correctly after the join operands are swapped in the first loop. */ - if (cur_left_neighbor && + if (same_level_left_neighbor && cur_table_ref->outer_join & JOIN_TYPE_RIGHT) { /* This can happen only for JOIN ... ON. */ DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2); - swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref); + swap_variables(TABLE_LIST*, same_level_left_neighbor, cur_table_ref); } + /* + Pick the parent's left and right neighbors if there are no immediate + neighbors at the same level. + */ + real_left_neighbor= (same_level_left_neighbor) ? + same_level_left_neighbor : left_neighbor; + real_right_neighbor= (same_level_right_neighbor) ? + same_level_right_neighbor : right_neighbor; + if (cur_table_ref->nested_join && store_top_level_join_columns(thd, cur_table_ref, - cur_left_neighbor, cur_right_neighbor)) + real_left_neighbor, real_right_neighbor)) goto err; - cur_right_neighbor= cur_table_ref; + same_level_right_neighbor= cur_table_ref; } } From 8024aabb76ffa8d1ea6105ca071b2109766ea2cb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 17:59:52 +0300 Subject: [PATCH 27/42] Bug #20868: Client connection is broken on SQL query error An aggregate function reference was resolved incorrectly and caused a crash in count_field_types. Must use real_item() to get to the real Item instance through the reference mysql-test/r/func_group.result: Bug #20868: Client connection is broken on SQL query error * test case for the bug mysql-test/t/func_group.test: Bug #20868: Client connection is broken on SQL query error * test case for the bug sql/sql_select.cc: Bug #20868: Client connection is broken on SQL query error * correctly resolve aggregate function references. --- mysql-test/r/func_group.result | 11 +++++++++++ mysql-test/t/func_group.test | 15 +++++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index f693c6190d5..896b79297f8 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -988,3 +988,14 @@ SUM(a) 6 DROP TABLE t1; set div_precision_increment= @sav_dpi; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); +SELECT SQL_NO_CACHE +(SELECT SUM(c.a) FROM t1 ttt, t2 ccc +WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; +minid +NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index e8c5fa18a25..f28ce234b73 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -660,3 +660,18 @@ SELECT SUM(a) FROM t1 GROUP BY b/c; DROP TABLE t1; set div_precision_increment= @sav_dpi; +# +# Bug #20868: Client connection is broken on SQL query error +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); + +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); + +SELECT SQL_NO_CACHE + (SELECT SUM(c.a) FROM t1 ttt, t2 ccc + WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; + +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..c31d9d9902b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12806,7 +12806,7 @@ count_field_types(TMP_TABLE_PARAM *param, List &fields, { if (! field->const_item()) { - Item_sum *sum_item=(Item_sum*) field; + Item_sum *sum_item=(Item_sum*) field->real_item(); if (!sum_item->quick_group) param->quick_group=0; // UDF SUM function param->sum_func_count++; From 7118c2523c2b8d127ae0e3f2a08f28ee11c1c712 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 20:44:35 +0300 Subject: [PATCH 28/42] Bug #20466: a view is mixing data when there's a trigger on the table When making a place to store field values at the start of each group the real item (not the reference) must be used when deciding which column to copy. mysql-test/r/group_by.result: Bug #20466: a view is mixing data when there's a trigger on the table - test suite for the bug mysql-test/t/group_by.test: Bug #20466: a view is mixing data when there's a trigger on the table - test suite for the bug sql/sql_select.cc: Bug #20466: a view is mixing data when there's a trigger on the table - deal correctly with references --- mysql-test/r/group_by.result | 25 +++++++++++++++++++++++++ mysql-test/t/group_by.test | 23 +++++++++++++++++++++++ sql/sql_select.cc | 16 +++++++++------- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7bc886022cc..e5c177503fa 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -796,3 +796,28 @@ aaa show warnings; Level Code Message drop table t1, t2; +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), +(25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), +(17,25), (10,54), (5,62),(3,68); +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index b b 2 NULL 10 Using index +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 1 test.t2.b 1 +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +a b real_b +1 ----- ----- +6 Allemagne Allemagne +17 Autriche Autriche +25 Belgique Belgique +54 Danemark Danemark +62 Espagne Espagne +68 France France +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index fb9835c5d7f..ce1e4e59600 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -632,3 +632,26 @@ group by t1.c1; show warnings; drop table t1, t2; +# +# Bug #20466: a view is mixing data when there's a trigger on the table +# +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); + +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), + (25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); + +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); + +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), + (17,25), (10,54), (5,62),(3,68); + +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; + +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; + +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..39f5b43b05e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13066,10 +13066,11 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->real_item()->type() == Item::FIELD_ITEM) + Item *real_pos= pos->real_item(); + if (real_pos->type() == Item::FIELD_ITEM) { Item_field *item; - pos= pos->real_item(); + pos= real_pos; if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -13108,12 +13109,13 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, } } } - else if ((pos->type() == Item::FUNC_ITEM || - pos->type() == Item::SUBSELECT_ITEM || - pos->type() == Item::CACHE_ITEM || - pos->type() == Item::COND_ITEM) && - !pos->with_sum_func) + else if ((real_pos->type() == Item::FUNC_ITEM || + real_pos->type() == Item::SUBSELECT_ITEM || + real_pos->type() == Item::CACHE_ITEM || + real_pos->type() == Item::COND_ITEM) && + !real_pos->with_sum_func) { // Save for send fields + pos= real_pos; /* TODO: In most cases this result will be sent to the user. This should be changed to use copy_int or copy_real depending From 35209c68eab3137bf40ca1657a2404006c2aa392 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 02:08:00 +0400 Subject: [PATCH 29/42] Fixed bug#12185: Data type aggregation may produce wrong result The Item::tmp_table_field_from_field_type() function creates Field_datetime object instead of Field_timestamp object for timestamp field thus always changing data type is a tmp table is used. The Field_blob object constructor which is used in the Item::tmp_table_field_from_field_type() is always setting packlength field of newly created blob to 4. This leads to changing fields data type for example from the blob to the longblob if a temporary table is used. The Item::make_string_field() function always converts Field_string objects to Field_varstring objects. This leads to changing data type from the char/binary to varchar/varbinary. Added appropriate Field_timestamp object constructor for using in the Item::tmp_table_field_from_field_type() function. Added Field_blob object constructor which sets pack length according to max_length argument. The Item::tmp_table_field_from_field_type() function now creates Field_timestamp object for a timestamp field. The Item_type_holder::display_length() now returns correct NULL length NULL length. The Item::make_string_field() function now doesn't change Field_string to Field_varstring in the case of Item_type_holder. The Item::tmp_table_field_from_field_type() function now uses the Field_blob constructor which sets packlength according to max_length. mysql-test/t/union.test: Added test case for bug#12185: Data type aggregation may produce wrong result Corrected test case after fix for bug#12185 mysql-test/t/innodb.test: Corrected test case after fix for bug#12185 mysql-test/r/union.result: Added test case for bug#12185: Data type aggregation may produce wrong result Corrected test case after fix for bug#12185 mysql-test/r/innodb.result: Corrected test case after fix for bug#12185 mysql-test/r/create.result: Corrected the test case after fixing bug#12185 sql/field.h: Fixed bug#12185: Data type aggregation may produce wrong result Added Field_blob object constructor which sets packlength according to max_length argument. sql/item.cc: Fixed bug#12185: Data type aggregation may produce wrong result The Item::make_string_field() function now doesn't change Field_string to Field_varstring in the case of Item_type_holder. The Item::tmp_table_field_from_field_type() function now creates Field_timestamp object for a timestamp field. The Item::tmp_table_field_from_field_type() function now uses the Field_blob constructor which sets packlength according to max_length. The Item_type_holder::display_length() now returns correct NULL length NULL length. sql/field.cc: Fixed bug#12185: Data type aggregation may produce wrong result Added appropriate Field_timestamp object constructor for using in the Item::tmp_table_field_from_field_type() function. --- mysql-test/r/create.result | 2 +- mysql-test/r/innodb.result | 4 ++-- mysql-test/r/union.result | 31 +++++++++++++++++++++++-------- mysql-test/t/innodb.test | 2 +- mysql-test/t/union.test | 12 ++++++++++-- sql/field.cc | 18 ++++++++++++++++++ sql/field.h | 17 +++++++++++++++++ sql/item.cc | 13 ++++++++++--- 8 files changed, 82 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 27a6c8a9d03..0bc5ec32086 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -452,7 +452,7 @@ t2 CREATE TABLE `t2` ( `ifnull(h,h)` decimal(5,4) default NULL, `ifnull(i,i)` year(4) default NULL, `ifnull(j,j)` date default NULL, - `ifnull(k,k)` datetime NOT NULL default '0000-00-00 00:00:00', + `ifnull(k,k)` timestamp NOT NULL default '0000-00-00 00:00:00', `ifnull(l,l)` datetime default NULL, `ifnull(m,m)` varchar(1) default NULL, `ifnull(n,n)` varchar(3) default NULL, diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 77046cc1fd1..1d1f26e4b01 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1473,8 +1473,8 @@ Error 1146 Table 'test.t4' doesn't exist drop table t1,t2,t3; create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select name2 from t1 union all select name from t1 union all select id from t1; -name2 +select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; +trim(name2) fff sss ttt diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index eb9e10aa58d..6ef5363d90f 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -691,9 +691,9 @@ t1 CREATE TABLE `t1` ( `da` datetime default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -create table t1 SELECT dt from t2 UNION select sc from t2; -select * from t1; -dt +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; +trim(dt) 1972-10-22 11:50:00 testc show create table t1; @@ -732,7 +732,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `dt` longblob + `dt` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT sv from t2 UNION select b from t2; @@ -743,7 +743,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `sv` longblob + `sv` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; @@ -755,7 +755,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `i` longblob + `i` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT sv from t2 UNION select tx from t2; @@ -766,7 +766,7 @@ teeeeeeeeeeeest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `sv` longtext + `sv` text ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT b from t2 UNION select tx from t2; @@ -777,7 +777,7 @@ teeeeeeeeeeeest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `b` longblob + `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2; create table t1 select 1 union select -1; @@ -1306,3 +1306,18 @@ id 5 99 drop table t1; +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` char(1) default NULL, + `f2` char(5) default NULL, + `f3` binary(1) default NULL, + `f4` binary(5) default NULL, + `f5` timestamp NOT NULL default '0000-00-00 00:00:00', + `f6` varchar(1) character set utf8 default NULL, + `f7` text, + `f8` text character set utf8 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e4c8bf89cca..4ebfef3504e 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1079,7 +1079,7 @@ drop table t1,t2,t3; # create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select name2 from t1 union all select name from t1 union all select id from t1; +select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; drop table t1; # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 692f1f509fa..516bc6d4818 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -390,8 +390,8 @@ create table t1 SELECT da from t2 UNION select dt from t2; select * from t1; show create table t1; drop table t1; -create table t1 SELECT dt from t2 UNION select sc from t2; -select * from t1; +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; show create table t1; drop table t1; create table t1 SELECT dt from t2 UNION select sv from t2; @@ -793,3 +793,11 @@ select id from t1 union all select 99 order by 1; drop table t1; # End of 4.1 tests + +# +# Bug#12185: Data type aggregation may produce wrong result +# +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +drop table t1, t2; diff --git a/sql/field.cc b/sql/field.cc index a920d6d91b1..163822fe712 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4484,6 +4484,24 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, } +Field_timestamp::Field_timestamp(bool maybe_null_arg, + const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) +{ + /* For 4.0 MYD and 4.0 InnoDB compatibility */ + flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + if (table && !table->timestamp_field && + unireg_check != NONE) + { + /* This timestamp has auto-update */ + table->timestamp_field= this; + flags|=TIMESTAMP_FLAG; + } +} + + /* Get auto-set type for TIMESTAMP field. diff --git a/sql/field.h b/sql/field.h index f4d27e46877..3aeb5e03259 100644 --- a/sql/field.h +++ b/sql/field.h @@ -781,6 +781,8 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs); + Field_timestamp(bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs); enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } @@ -1129,6 +1131,21 @@ public: { flags|= BLOB_FLAG; } + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs, bool set_packlength) + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) + { + flags|= BLOB_FLAG; + packlength= 4; + if (set_packlength) + { + uint32 char_lengt= len_arg/cs->mbmaxlen; + packlength= char_length <= 255 ? 1 : + char_length <= 65535 ? 2 : + char_length <= 16777215 ? 3 : 4; + } + } enum_field_types type() const { return FIELD_TYPE_BLOB;} enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } diff --git a/sql/item.cc b/sql/item.cc index 24efc1f106f..c7208a3af64 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3874,7 +3874,9 @@ Field *Item::make_string_field(TABLE *table) if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) return new Field_blob(max_length, maybe_null, name, table, collation.collation); - if (max_length > 0) + /* Item_type_holder holds the exact type, do not change it */ + if (max_length > 0 && + (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) return new Field_varstring(max_length, maybe_null, name, table, collation.collation); return new Field_string(max_length, maybe_null, name, table, @@ -3938,6 +3940,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_TIME: return new Field_time(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_TIMESTAMP: + return new Field_timestamp(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_DATETIME: return new Field_datetime(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_YEAR: @@ -3961,7 +3964,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: - return new Field_blob(max_length, maybe_null, name, table, + if (this->type() == Item::TYPE_HOLDER) + return new Field_blob(max_length, maybe_null, name, table, + collation.collation, 1); + else + return new Field_blob(max_length, maybe_null, name, table, collation.collation); break; // Blob handled outside of case } @@ -6117,7 +6124,7 @@ uint32 Item_type_holder::display_length(Item *item) case MYSQL_TYPE_DOUBLE: return 53; case MYSQL_TYPE_NULL: - return 4; + return 0; case MYSQL_TYPE_LONGLONG: return 20; case MYSQL_TYPE_INT24: From 9d432f0dae740bcaa89b61a9b8fced23030d5a13 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 02:36:17 +0400 Subject: [PATCH 30/42] Add missing "DROP TABLE" clause --- mysql-test/r/subselect.result | 1 + mysql-test/t/subselect.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 595d80f1218..a2a88be8c42 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2894,3 +2894,4 @@ s1 select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); s1 2 +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1bcd37dd7d7..fc97d22cbb1 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1860,4 +1860,5 @@ select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); select * from t1 where (s1 = ALL (select s1/s1 from t1)); select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +drop table t1; # End of 4.1 tests From 5a3a1c98a42fbb045303f766f53bfdd033ed795c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 05:52:37 +0400 Subject: [PATCH 31/42] field.h: Fixed typo. sql/field.h: Fixed typo. --- sql/field.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/field.h b/sql/field.h index 0bbcd1099a0..d89d8bb3965 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1141,7 +1141,7 @@ public: packlength= 4; if (set_packlength) { - uint32 char_lengt= len_arg/cs->mbmaxlen; + uint32 char_length= len_arg/cs->mbmaxlen; packlength= char_length <= 255 ? 1 : char_length <= 65535 ? 2 : char_length <= 16777215 ? 3 : 4; From 0f5797f57697750a6177e4dbe3c04a4fefcdae41 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 16:18:28 +0400 Subject: [PATCH 32/42] Post-merge fixes --- sql/item_subselect.cc | 2 +- sql/mysql_priv.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3c279d827b2..6675c9e7b25 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -575,7 +575,7 @@ Item_allany_subselect::Item_allany_subselect(Item * left_exp, chooser_compare_func_creator fc, st_select_lex *select_lex, bool all_arg) - :Item_in_subselect(), all(all_arg), func_creator(fc) + :Item_in_subselect(), func_creator(fc), all(all_arg) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 619755fc6ff..3298b4e6c8e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -523,6 +523,8 @@ class sys_var; class Comp_creator; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); #include "item.h" +extern my_decimal decimal_zero; + /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); From 43df9fd34c2d2b05a29b17e39920ab270f82d483 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 12:44:54 -0700 Subject: [PATCH 33/42] Fixed bug #18925: wrong results for queries with subqueries on information schema that use MIN/MAX aggregation. Execution of some correlated subqueries may set the value of null_row to 1 for tables used in the subquery. If the the subquery is on information schema it causes rejection of any row for the following executions of the subquery in the case when an optimization filtering by some condition is applied. The fix restores the value of the null_row flag for each execution of a subquery on information schema. mysql-test/r/information_schema.result: Added a test case for bug #18925. mysql-test/t/information_schema.test: Added a test case for bug #18925. sql/sql_show.cc: Fixed bug #18925. Execution of some correlated subqueries may set the value of null_row to 1 for tables used in the subquery. If the the subquery is on information schema it causes rejection of any row for the following execitions of the subquery in the case when an optimization filtering by some condition is applied. The fix restores the value of the null_row flag for each execution of a subquery on information schema. --- mysql-test/r/information_schema.result | 62 ++++++++++++++++++++++++++ mysql-test/t/information_schema.test | 33 ++++++++++++++ sql/sql_show.cc | 1 + 3 files changed, 96 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index a2feba7ad5d..3b3669119d5 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1170,3 +1170,65 @@ f1() DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = t.table_schema AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = 'information_schema' AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index a2e19112cf9..b49ec9e2f31 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -887,4 +887,37 @@ DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; +# +# Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA +# + +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = t.table_schema AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = 'information_schema' AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); + # End of 5.0 tests. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cabb04c5f16..e2adefb0ca9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3963,6 +3963,7 @@ bool get_schema_tables_result(JOIN *join) table_list->table->file->delete_all_rows(); free_io_cache(table_list->table); filesort_free_buffers(table_list->table); + table_list->table->null_row= 0; } else table_list->table->file->records= 0; From d64f605e48d42bc9a8fa33e206e427eab69b1a24 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Jul 2006 19:05:46 -0700 Subject: [PATCH 34/42] Fixed bug #21231: wrong results for a simple query with a a non-correlated single-row subquery over information schema. The function get_all_tables filling all information schema tables reset lex->sql_command to SQLCOM_SHOW_FIELDS. After this the function could evaluate partial conditions related to some columns. If these conditions contained a subquery over information schema it led to a wrong evaluation and a wrong result set. This bug was already fixed in 5.1. This patch follows the way how it was done in 5.1 where the value of lex->sql_command is set to SQLCOM_SHOW_FIELDS in get_all_tables only for the calls of the function open_normal_and_derived_tables and is restored after these calls. mysql-test/r/information_schema.result: Added a test case for bug #21231. mysql-test/t/information_schema.test: Added a test case for bug #21231. --- mysql-test/r/information_schema.result | 8 ++++++++ mysql-test/t/information_schema.test | 10 ++++++++++ sql/sql_show.cc | 16 ++++++++++------ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 3b3669119d5..652af1c8387 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1232,3 +1232,11 @@ TABLE_PRIVILEGES TABLE_SCHEMA TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE VIEWS TABLE_SCHEMA +SELECT MAX(table_name) FROM information_schema.tables; +MAX(table_name) +VIEWS +SELECT table_name from information_schema.tables +WHERE table_name=(SELECT MAX(table_name) +FROM information_schema.tables); +table_name +VIEWS diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b49ec9e2f31..9e5dac8b853 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -920,4 +920,14 @@ SELECT t.table_name, c1.column_name c2.column_name LIKE '%SCHEMA%' ); +# +# Bug#21231: query with a simple non-correlated subquery over +# INFORMARTION_SCHEMA.TABLES +# + +SELECT MAX(table_name) FROM information_schema.tables; +SELECT table_name from information_schema.tables + WHERE table_name=(SELECT MAX(table_name) + FROM information_schema.tables); + # End of 5.0 tests. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e2adefb0ca9..e22873dad9a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2116,12 +2116,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LINT_INIT(end); LINT_INIT(len); - /* - Let us set fake sql_command so views won't try to merge - themselves into main statement. - */ - lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->reset_n_backup_query_tables_list(&query_tables_list_backup); /* @@ -2144,8 +2138,16 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) I_S tables will be done. */ thd->temporary_tables= open_tables_state_backup.temporary_tables; + /* + Let us set fake sql_command so views won't try to merge + themselves into main statement. If we don't do this, + SELECT * from information_schema.xxxx will cause problems. + SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' + */ + lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + lex->sql_command= save_sql_command; /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() @@ -2267,8 +2269,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; lex->all_selects_list= &sel; lex->derived_tables= 0; + lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + lex->sql_command= save_sql_command; /* We should use show_table_list->alias instead of show_table_list->table_name because table_name From 4e7121c07b0cfb5ed39e25edd9022ba1811d65fa Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 11:45:10 +0300 Subject: [PATCH 35/42] Bug#16712: group_concat returns odd srting insead of intended result when calculating GROUP_CONCAT all blob fields are transformed to varchar when making the temp table. However a varchar has at max 2 bytes for length. This fix makes the conversion only for blobs whose max length is below that limit. Otherwise blob field is created by make_string_field() call. mysql-test/r/func_gconcat.result: Bug#16712: group_concat returns odd srting insead of intended result * testsuite for the bug mysql-test/t/func_gconcat.test: Bug#16712: group_concat returns odd srting insead of intended result * testsuite for the bug sql/item_sum.cc: Bug#16712: group_concat returns odd srting insead of intended result * force blob->varchar conversion for small enough blobs only sql/sql_select.cc: Bug#16712: group_concat returns odd srting insead of intended result * force blob->varchar conversion for small enough blobs only --- mysql-test/r/func_gconcat.result | 13 +++++++++++++ mysql-test/t/func_gconcat.test | 14 ++++++++++++++ sql/item_sum.cc | 8 +++++++- sql/sql_select.cc | 14 ++++++++++++-- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index d8a539da3fe..dc09a68682c 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -641,3 +641,16 @@ select charset(group_concat(c1 order by c2)) from t1; charset(group_concat(c1 order by c2)) latin1 drop table t1; +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); +SET GROUP_CONCAT_MAX_LEN = 20000000; +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; +SELECT a, CHAR_LENGTH(b) FROM t1; +a CHAR_LENGTH(b) +1 120000 +2 120000 +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +CHAR_LENGTH( GROUP_CONCAT(b) ) +240001 +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index fbfdfa3b5d0..98c21986aa9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -433,3 +433,17 @@ create table t1 (c1 varchar(10), c2 int); select charset(group_concat(c1 order by c2)) from t1; drop table t1; +# +# Bug #16712: group_concat returns odd string instead of intended result +# +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); + +SET GROUP_CONCAT_MAX_LEN = 20000000; + +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; + +SELECT a, CHAR_LENGTH(b) FROM t1; +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 877eb908d27..69b93909b3c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -377,7 +377,13 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, case INT_RESULT: return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); case STRING_RESULT: - if (max_length/collation.collation->mbmaxlen > 255 && convert_blob_length) + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ + if (max_length/collation.collation->mbmaxlen > 255 && + max_length/collation.collation->mbmaxlen < UINT_MAX16 && + convert_blob_length) return new Field_varstring(convert_blob_length, maybe_null, name, table, collation.collation); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 41ff9185cfb..6f3e6d8868d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8011,7 +8011,12 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field, { Field *new_field; - if (convert_blob_length && (org_field->flags & BLOB_FLAG)) + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ + if (convert_blob_length && convert_blob_length < UINT_MAX16 && + (org_field->flags & BLOB_FLAG)) new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(), org_field->field_name, table, @@ -8087,8 +8092,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table); + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ else if (item->max_length/item->collation.collation->mbmaxlen > 255 && - convert_blob_length) + item->max_length/item->collation.collation->mbmaxlen < UINT_MAX16 + && convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, item->name, table, item->collation.collation); From 1b3cdb6085c944e1c371779d4d4b6473ebcd116d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 18:42:49 +0300 Subject: [PATCH 36/42] Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called When executing INSERT over a view with calculated columns it was assuming all elements of the fields collection are actually Item_field instances. This may not be true when inserting into a view and that view has columns that are such expressions that allow updating (like setting a collation for example). Corrected to access field information through the filed_for_view_update() function and retrieve correctly the field info even for "update-friendly" non-Item_field items. mysql-test/r/view.result: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - test suite mysql-test/t/view.test: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - test suite sql/item_strfunc.h: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - obvious typo fixed sql/sql_base.cc: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - must access field information through the filed_for_view_update() function to retrieve correctly the field info even for "update-friendly" non-Item_field items. --- mysql-test/r/view.result | 13 +++++++++++++ mysql-test/t/view.test | 19 +++++++++++++++++++ sql/item_strfunc.h | 2 +- sql/sql_base.cc | 9 +++++++-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index c8a673e2209..b2c65423b59 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2807,3 +2807,16 @@ yadda yad DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (s1 char); +INSERT INTO t1 VALUES ('Z'); +CREATE VIEW v1 AS SELECT s1 collate latin1_german1_ci AS col FROM t1; +CREATE VIEW v2 (col) AS SELECT s1 collate latin1_german1_ci FROM t1; +INSERT INTO v1 (col) VALUES ('b'); +INSERT INTO v2 (col) VALUES ('c'); +SELECT s1 FROM t1; +s1 +Z +b +c +DROP VIEW v1, v2; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 6399cef9086..1b930353ca4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2667,3 +2667,22 @@ SELECT * FROM v1; DROP VIEW v1; DROP TABLE t1; + +# +# Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE +# clause is called +# +CREATE TABLE t1 (s1 char); +INSERT INTO t1 VALUES ('Z'); + +CREATE VIEW v1 AS SELECT s1 collate latin1_german1_ci AS col FROM t1; + +CREATE VIEW v2 (col) AS SELECT s1 collate latin1_german1_ci FROM t1; + +# either of these statements will cause crash +INSERT INTO v1 (col) VALUES ('b'); +INSERT INTO v2 (col) VALUES ('c'); + +SELECT s1 FROM t1; +DROP VIEW v1, v2; +DROP TABLE t1; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index a72182abcf7..488dc20b063 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -728,7 +728,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } - enum Functype func_type() const { return COLLATE_FUNC; } + enum Functype functype() const { return COLLATE_FUNC; } void print(String *str); Item_field *filed_for_view_update() { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7f9076bb46e..28edee5c729 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4959,12 +4959,17 @@ fill_record(THD * thd, List &fields, List &values, bool ignore_errors) { List_iterator_fast f(fields),v(values); - Item *value; + Item *value, *fld; Item_field *field; DBUG_ENTER("fill_record"); - while ((field=(Item_field*) f++)) + while ((fld= f++)) { + if (!(field= fld->filed_for_view_update())) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name); + DBUG_RETURN(TRUE); + } value=v++; Field *rfield= field->field; TABLE *table= rfield->table; From 9a63adc8fd18489aa3a75c7715abaea0dcd16349 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 00:31:29 +0400 Subject: [PATCH 37/42] Fixed bug#19862: Sort with filesort by function evaluates function twice When there is no index defined filesort is used to sort the result of a query. If there is a function in the select list and the result set should be ordered by it's value then this function will be evaluated twice. First time to get the value of the sort key and second time to send its value to a user. This happens because filesort when sorts a table remembers only values of its fields but not values of functions. All functions are affected. But taking into account that SP and UDF functions can be both expensive and non-deterministic a temporary table should be used to store their results and then sort it to avoid twice SP evaluation and to get a correct result. If an expression referenced in an ORDER clause contains a SP or UDF function, force the use of a temporary table. A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. mysql-test/t/udf.test: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/t/sp.test: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/r/sp.result: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/r/udf.result: Added test case for bug#19862: Sort with filesort by function evaluates function twice sql/sql_select.cc: Fixed bug#19862: Sort with filesort by function evaluates function twice If an expression referenced in an ORDER clause contains a SP or UDF function, force the use of a temporary table. sql/item_func.h: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. sql/item.h: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. sql/item_func.cc: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. --- mysql-test/r/sp.result | 19 +++++++++++++++++++ mysql-test/r/udf.result | 6 ++++++ mysql-test/t/sp.test | 18 ++++++++++++++++++ mysql-test/t/udf.test | 7 +++++++ sql/item.h | 1 + sql/item_func.cc | 7 +++++++ sql/item_func.h | 4 +++- sql/sql_select.cc | 20 ++++++++++++++++++++ 8 files changed, 81 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 50913fb1b90..f04b5b2c635 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -5057,4 +5057,23 @@ concat('data was: /', var1, '/') data was: /1/ drop table t3| drop procedure bug15217| +drop procedure if exists bug19862| +CREATE TABLE t11 (a INT)| +CREATE TABLE t12 (a INT)| +CREATE FUNCTION bug19862(x INT) RETURNS INT +BEGIN +INSERT INTO t11 VALUES (x); +RETURN x+1; +END| +INSERT INTO t12 VALUES (1), (2)| +SELECT bug19862(a) FROM t12 ORDER BY 1| +bug19862(a) +2 +3 +SELECT * FROM t11| +a +1 +2 +DROP TABLE t11, t12| +DROP FUNCTION bug19862| drop table t1,t2; diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 484c42c41bf..b44dce14230 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -93,6 +93,12 @@ NULL 0R FR DROP TABLE bug19904; +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +drop table t1; End of 5.0 tests. DROP FUNCTION metaphon; DROP FUNCTION myfunc_double; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 25c96042e6f..cb9972fb800 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5962,6 +5962,24 @@ call bug15217()| drop table t3| drop procedure bug15217| +# +# BUG#19862: Sort with filesort by function evaluates function twice +# +--disable_warnings +drop procedure if exists bug19862| +--enable_warnings +CREATE TABLE t11 (a INT)| +CREATE TABLE t12 (a INT)| +CREATE FUNCTION bug19862(x INT) RETURNS INT + BEGIN + INSERT INTO t11 VALUES (x); + RETURN x+1; + END| +INSERT INTO t12 VALUES (1), (2)| +SELECT bug19862(a) FROM t12 ORDER BY 1| +SELECT * FROM t11| +DROP TABLE t11, t12| +DROP FUNCTION bug19862| # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index f3be08c8537..560ec88eb10 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -109,6 +109,13 @@ SELECT myfunc_double(n) AS f FROM bug19904; SELECT metaphon(v) AS f FROM bug19904; DROP TABLE bug19904; +# +# Bug#19862: Sort with filesort by function evaluates function twice +# +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +drop table t1; --echo End of 5.0 tests. # diff --git a/sql/item.h b/sql/item.h index 0f49145082f..c59d84aaeaa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -752,6 +752,7 @@ public: virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; } + virtual bool func_type_checker_processor(byte *arg) { return 0; } virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 1d906b300b6..c31ac2bf047 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -398,6 +398,13 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) return res; } + +bool Item_func::func_type_checker_processor(byte *arg) +{ + return *((Functype*)arg) == functype(); +} + + my_decimal *Item_func::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed); diff --git a/sql/item_func.h b/sql/item_func.h index 2ca4be9f3f2..88a52d7f46e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -55,7 +55,7 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -186,6 +186,7 @@ public: Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); + bool func_type_checker_processor(byte *arg); }; @@ -930,6 +931,7 @@ public: Item_udf_func(udf_func *udf_arg, List &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } + enum Functype functype() const { return UDF_FUNC; } bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..14389a57465 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1064,6 +1064,26 @@ JOIN::optimize() { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + if (order) + { + /* + Force using of tmp table if sorting by a SP or UDF function due to + their expensive and probably non-deterministic nature. + */ + for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next) + { + Item *item= *tmp_order->item; + Item_func::Functype type=Item_func::FUNC_SP; + Item_func::Functype type1=Item_func::UDF_FUNC; + if (item->walk(&Item::func_type_checker_processor,(byte*)&type) || + item->walk(&Item::func_type_checker_processor,(byte*)&type1)) + { + /* Force tmp table without sort */ + need_tmp=1; simple_order=simple_group=0; + break; + } + } + } } tmp_having= having; From 585b5bbc922f9b8a972f7b8d54c93c5eb3683b22 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 01:11:19 +0300 Subject: [PATCH 38/42] Fix for BUG#20954: avg(keyval) retuns 0.38 but max(keyval) returns an empty set The problem was in that opt_sum_query() replaced MIN/MAX functions with the corresponding constant found in a key, but due to imprecise representation of float numbers, when evaluating the where clause, this comparison failed. When MIN/MAX optimization detects that all tables can be removed, also remove all conjuncts in a where clause that refer to these tables. As a result of this fix, these conditions are not evaluated twice, and in the case of float number comparisons we do not discard result rows due to imprecise float representation. As a side-effect this fix also corrects an unnoticed problem in bug 12882. mysql-test/r/func_group.result: BUG#20954 - test result adjustment. Adjusted the test result of bug 12882 which was not preperly fixed. The current patch corrects the problem that was fully corrected by the patch for 12882. The problem was that opt_sum_query() indicated that the optimizer may remove all tables because all MIN/MAX/COUNT functions are constants, but this lead to an empty result instead of NULL because the WHERE clause was still evaluated. The current fix removes all conjuncts in the where clause that reference the removed tables, and thus corrects the problem. mysql-test/r/select.result: BUG#20954 - added test mysql-test/r/subselect.result: BUG#20954 - test result adjustment. The fix removes those conditions in a where clause that refer to tables optimized away by MIN/MAX optimization (opt_sum_query()). mysql-test/t/select.test: BUG#20954 - added test sql/sql_select.cc: Fix for BUG#20954: avg(keyval) retuns 0.38 but max(keyval) returns an empty set When MIN/MAX optimization detects that all tables can be removed, also remove all conjuncts in a where clause that refer to these tables. As a result of this fix, these conditions are not evaluated twice, and in the case of float number comparisons we do not discard result rows due to imprecise float representation. As a side-effect this fix also corrects an unnoticed problem in bug 12882. --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/select.result | 49 ++++++++++++++++++++++++++++++++++ mysql-test/r/subselect.result | 2 +- mysql-test/t/select.test | 30 +++++++++++++++++++++ sql/sql_select.cc | 18 +++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index ffa68f279f3..932ef133087 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -824,6 +824,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 @@ -835,6 +836,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 c7df11ab018..d7c01fa5a57 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2744,3 +2744,52 @@ SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01) i in ('1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); +explain select max(key1) from t1 where key1 <= 0.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key2) from t2 where key2 <= 1.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key2) from t2 where key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(key1) from t1 where key1 <= 0.6158; +max(key1) +0.61580002307892 +select max(key2) from t2 where key2 <= 1.6158; +max(key2) +1.6158000230789 +select min(key1) from t1 where key1 >= 0.3762; +min(key1) +0.37619999051094 +select min(key2) from t2 where key2 >= 1.3762; +min(key2) +1.3761999607086 +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +max(key1) min(key2) +0.61580002307892 1.3761999607086 +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +max(key1) +0.61580002307892 +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +min(key1) +0.37619999051094 +DROP TABLE t1,t2; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 595d80f1218..dc921f747ee 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -539,7 +539,7 @@ EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: -Note 1003 select max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 where (test.t1.numeropost = _latin1'1') +Note 1003 select max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 Using index diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 4cdfc220350..acf9fd77c1b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2297,4 +2297,34 @@ INSERT INTO t1 VALUES (10); SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; DROP TABLE t1; +# +# Bug #20954 "avg(keyval) retuns 0.38 but max(keyval) returns an empty set" +# +--disable_ps_protocol +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); + +explain select max(key1) from t1 where key1 <= 0.6158; +explain select max(key2) from t2 where key2 <= 1.6158; +explain select min(key1) from t1 where key1 >= 0.3762; +explain select min(key2) from t2 where key2 >= 1.3762; +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +select max(key1) from t1 where key1 <= 0.6158; +select max(key2) from t2 where key2 <= 1.6158; +select min(key1) from t1 where key1 >= 0.3762; +select min(key2) from t2 where key2 >= 1.3762; +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +DROP TABLE t1,t2; +--enable_ps_protocol + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..96ac98cfb88 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -547,6 +547,24 @@ JOIN::optimize() } zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved + /* + Extract all table-independent conditions and replace the WHERE + clause with them. All other conditions were computed by opt_sum_query + and the MIN/MAX/COUNT function(s) have been replaced by constants, + so there is no need to compute the whole WHERE clause again. + Notice that make_cond_for_table() will always succeed to remove all + computed conditions, because opt_sum_query() is applicable only to + conjunctions. + */ + if (conds) + { + COND *table_independent_conds= + make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0); + DBUG_EXECUTE("where", + print_where(table_independent_conds, + "where after opt_sum_query()");); + conds= table_independent_conds; + } } } if (!tables_list) From 5ca1ee5eea4d08491772388f39a664e21df32b9b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 13:32:28 +0300 Subject: [PATCH 39/42] Bug #21019: First result of SELECT COUNT(*) different than consecutive runs When optimizing conditions like 'a = OR a IS NULL' so that they're united into a single condition on the key and checked together the server must check which value is the NULL value in a correct way : not only using ->is_null but also check if the expression doesn't depend on any tables referenced in the current statement. This additional check must be performed because that optimization takes place before the actual execution of the statement, so if the field was initialized to NULL from a previous statement the optimization would be applied incorrectly. mysql-test/r/select.result: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - test case mysql-test/t/select.test: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - test case. Note that ALTER TABLE is important here : it happens to leave the Field instance for t1.b set to NULL, witch is vital for demonstrating the problem fixed by this changeset. sql/sql_select.cc: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - check whether a value is null taking into account its table dependency. --- mysql-test/r/select.result | 26 ++++++++++++++++++++++++++ mysql-test/t/select.test | 15 +++++++++++++++ sql/sql_select.cc | 7 +++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index c7df11ab018..d415c336715 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2744,3 +2744,29 @@ SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01) i in ('1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +DROP TABLE IF EXISTS t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 4cdfc220350..23fc09b5e39 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2297,4 +2297,19 @@ INSERT INTO t1 VALUES (10); SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; DROP TABLE t1; +# +# Bug #21019: First result of SELECT COUNT(*) different than consecutive runs +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); + +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; + +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +DROP TABLE IF EXISTS t1,t2; # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..77ad0b8b163 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2143,8 +2143,11 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, /* field = expression OR field IS NULL */ old->level= and_level; old->optimize= KEY_OPTIMIZE_REF_OR_NULL; - /* Remember the NOT NULL value */ - if (old->val->is_null()) + /* + Remember the NOT NULL value unless the value does not depend + on other tables. + */ + if (!old->val->used_tables() && old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ old->null_rejecting= 0; From 8c92143b4bf715abd307b69a7f3637feec7df2ba Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 18:18:34 +0300 Subject: [PATCH 40/42] Bug #21019: First result of SELECT COUNT(*) different than consecutive runs Correct merge --- mysql-test/r/select.result | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 69228d2ff44..32c9fabb19e 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2736,6 +2736,32 @@ SELECT i='1e+01',i=1e+01, i in (1e+01,1e+01), i in ('1e+01','1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01,1e+01) i in ('1e+01','1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1 ( K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', @@ -3125,32 +3151,6 @@ select count(*) from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; count(*) 6 -CREATE TABLE t1 (a int, b int); -INSERT INTO t1 VALUES (1,1), (2,1), (4,10); -CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); -INSERT INTO t2 VALUES (1,NULL), (2,10); -ALTER TABLE t1 ENABLE KEYS; -EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index b b 5 NULL 2 Using index -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where -SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -a b a b -1 NULL 1 1 -1 NULL 2 1 -1 NULL 4 10 -2 10 4 10 -EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index b b 5 NULL 2 Using index -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where -SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -a b a b -1 NULL 1 1 -1 NULL 2 1 -1 NULL 4 10 -2 10 4 10 -DROP TABLE IF EXISTS t1,t2; drop table t1,t2,t3; create table t1 (a int); create table t2 (b int); From 6b75e24b73828316dd1715ab32811a614ce74314 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 19:19:30 +0300 Subject: [PATCH 41/42] * Bug #20792: Incorrect results from aggregate subquery When processing aggregate functions all tables values are reset to NULLs at the end of each group. When doing that if there are no rows found for a group the const tables must not be reset as they are not recalculated by do_select()/sub_select() for each group. mysql-test/r/subselect2.result: * Bug #20792: Incorrect results from aggregate subquery - test suite for the bug. This is dependent on InnoDB despite the fact that the bug and the fix are not InnoDB specific. This is because of the table flag HA_NOT_EXACT_COUNT. When this flag is off (as in MyISAM) both t2 and t3 become of join type 'system' as they are estimated to have 1 record and and this statistics can be trusted (according to the absence of HA_NOT_EXACT_COUNT). mysql-test/t/subselect2.test: * Bug #20792: Incorrect results from aggregate subquery - test suite for the bug sql/sql_select.cc: * Bug #20792: Incorrect results from aggregate subquery - when clearing results if there are not rows found for group the const tables must not be reset as they are not recalculated for each group. --- mysql-test/r/subselect2.result | 12 ++++++++++++ mysql-test/t/subselect2.test | 18 ++++++++++++++++++ sql/sql_select.cc | 10 ++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 8fcfa06a8ae..db1848105f8 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -130,3 +130,15 @@ id select_type table type possible_keys key key_len ref rows Extra 5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where 6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 32 func 1 Using index; Using where drop table t1, t2, t3, t4; +CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a int(10), PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 (a int(10), b int(10), c int(10), +PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t3 VALUES (1,2,1); +SELECT t1.* FROM t1 WHERE (SELECT COUNT(*) FROM t3,t2 WHERE t3.c=t2.a +and t2.a='1' AND t1.a=t3.b) > 0; +a +2 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index b21eda176b6..162bdd0d90a 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -150,3 +150,21 @@ EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JO drop table t1, t2, t3, t4; # End of 4.1 tests + +# +# Bug #20792: Incorrect results from aggregate subquery +# +CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (a int(10), PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t2 VALUES (1); + +CREATE TABLE t3 (a int(10), b int(10), c int(10), + PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t3 VALUES (1,2,1); + +SELECT t1.* FROM t1 WHERE (SELECT COUNT(*) FROM t3,t2 WHERE t3.c=t2.a + and t2.a='1' AND t1.a=t3.b) > 0; + +DROP TABLE t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..ce573136faf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4452,10 +4452,16 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_RETURN(0); } - +/* + used only in JOIN::clear +*/ static void clear_tables(JOIN *join) { - for (uint i=0 ; i < join->tables ; i++) + /* + must clear only the non-const tables, as const tables + are not re-calculated. + */ + for (uint i=join->const_tables ; i < join->tables ; i++) mark_as_null_row(join->table[i]); // All fields are NULL } From 1150869c4a6418b9dbcbe6b9b2f6036e1c5379f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 21:36:03 +0400 Subject: [PATCH 42/42] item_func.h, item_func.cc, sql_select.cc, item.h: Post review changes for bug#19862. sql/sql_select.cc: Post review changes for bug#19862. sql/item_func.h: Post review changes for bug#19862. sql/item_func.cc: Post review changes for bug#19862. sql/item.h: Post review changes for bug#19862. --- sql/item.h | 2 +- sql/item_func.cc | 4 ++-- sql/item_func.h | 5 ++++- sql/sql_select.cc | 5 +---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/item.h b/sql/item.h index c59d84aaeaa..514c31c2d74 100644 --- a/sql/item.h +++ b/sql/item.h @@ -752,7 +752,7 @@ public: virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; } - virtual bool func_type_checker_processor(byte *arg) { return 0; } + virtual bool is_expensive_processor(byte *arg) { return 0; } virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } diff --git a/sql/item_func.cc b/sql/item_func.cc index c31ac2bf047..cbab9a4de1b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -399,9 +399,9 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) } -bool Item_func::func_type_checker_processor(byte *arg) +bool Item_func::is_expensive_processor(byte *arg) { - return *((Functype*)arg) == functype(); + return is_expensive(); } diff --git a/sql/item_func.h b/sql/item_func.h index bac4a186867..b33dae092ac 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -189,7 +189,8 @@ public: Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); - bool func_type_checker_processor(byte *arg); + bool is_expensive_processor(byte *arg); + virtual bool is_expensive() { return 0; } }; @@ -947,6 +948,7 @@ public: void cleanup(); Item_result result_type () const { return udf.result_type(); } table_map not_null_tables() const { return 0; } + bool is_expensive() { return 1; } }; @@ -1475,6 +1477,7 @@ public: virtual enum Functype functype() const { return FUNC_SP; } bool fix_fields(THD *thd, Item **ref); + bool is_expensive() { return 1; } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36962a233b8..20945117da1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1073,10 +1073,7 @@ JOIN::optimize() for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next) { Item *item= *tmp_order->item; - Item_func::Functype type=Item_func::FUNC_SP; - Item_func::Functype type1=Item_func::UDF_FUNC; - if (item->walk(&Item::func_type_checker_processor,(byte*)&type) || - item->walk(&Item::func_type_checker_processor,(byte*)&type1)) + if (item->walk(&Item::is_expensive_processor,(byte*)0)) { /* Force tmp table without sort */ need_tmp=1; simple_order=simple_group=0;