From 7ac71fe4c23cdee67268ecec67dc8076c03eb800 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Aug 2005 12:02:06 -0700 Subject: [PATCH 01/48] Fix handling of libexecdir and sbindir in mysql.server, and note that basedir and datadir settings in script may be overwritten by settings in configuration files. (Bug #12550) support-files/mysql.server.sh: Note that basedir, datadir settings can be overwritten by configuration, and make sbindir and libexecdir distinct from bindir when setting it based on basedir. --- support-files/mysql.server.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 6757a1052a8..6dbffdc9778 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -39,7 +39,8 @@ # If you want to affect other MySQL variables, you should make your changes # in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files. -# If you change base dir, you must also change datadir +# If you change base dir, you must also change datadir. These may get +# overwritten by settings in the MySQL configuration files. basedir= datadir= @@ -61,8 +62,8 @@ then else bindir="$basedir/bin" datadir="$basedir/data" - sbindir="$basedir/bin" - libexecdir="$basedir/bin" + sbindir="$basedir/sbin" + libexecdir="$basedir/libexec" fi # @@ -99,8 +100,8 @@ parse_server_arguments() { --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` bindir="$basedir/bin" datadir="$basedir/data" - sbindir="$basedir/bin" - libexecdir="$basedir/bin" + sbindir="$basedir/sbin" + libexecdir="$basedir/libexec" ;; --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; @@ -240,7 +241,7 @@ case "$mode" in if test -x $libexecdir/mysqlmanager then manager=$libexecdir/mysqlmanager - elif test -x $bindir/mysqlmanager + elif test -x $sbindir/mysqlmanager then manager=$sbindir/mysqlmanager fi From 52758f7cd8b6d6ba9e4a652d87f142af5bda6697 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Aug 2005 15:36:47 +0500 Subject: [PATCH 02/48] Bug #12829 Cannot convert the charset of a GROUP_CONCAT result: item_sum.cc: "result" character set was not set into proper value. func_gconcat.result, func_gconcat.test: Fixing tests accordingly. sql/item_sum.cc: Bug #12829 Cannot convert the charset of a GROUP_CONCAT result: "result" character set was not set into proper value. mysql-test/t/func_gconcat.test: Bug #12829 mysql-test/r/func_gconcat.result: Bug #12829 --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 10 ++++++++++ sql/item_sum.cc | 1 + 3 files changed, 20 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 9faee3cbc01..ca615e28823 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1; ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat' drop table t1; drop table t2; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +a +À +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +À +DROP TABLE t1; CREATE TABLE t1 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 9793d0d0a2c..3fa72b364d9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -281,6 +281,16 @@ select collation(group_concat(a,b)) from t1; drop table t1; drop table t2; +# +# Bug #12829 +# Cannot convert the charset of a GROUP_CONCAT result +# +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +SELECT GROUP_CONCAT(a) FROM t1; +DROP TABLE t1; + # # bug #7769: group_concat returning null is checked in having # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 74a7fee113e..cb4107c4276 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1937,6 +1937,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args, arg_count, MY_COLL_ALLOW_CONV)) return 1; + result.set_charset(collation.collation); result_field= 0; null_value= 1; max_length= group_concat_max_len; From 1a170dc092f3f65b58ea4f22e3f663a470e2ab0b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Aug 2005 17:22:19 +0400 Subject: [PATCH 03/48] Fixes bug #12517. Clear user variables and replication events before closing temp tables in thread cleanup. mysql-test/r/connect.result: added results for test of bug #12517 mysql-test/t/connect.test: added test of bug #12517 sql/sql_class.cc: Clear user variables and replication events before closing temp tables in thread cleanup. --- mysql-test/r/connect.result | 16 ++++++++++++++++ mysql-test/t/connect.test | 18 ++++++++++++++++++ sql/sql_class.cc | 4 ++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index edf30e7f6e4..293ad37c31a 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -65,3 +65,19 @@ show tables; Tables_in_test delete from mysql.user where user=_binary"test"; flush privileges; +use test; +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (id integer not null auto_increment primary key); +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +use test; +drop table if exists t2; +Warnings: +Note 1051 Unknown table 't2' +drop table if exists t1; diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 1a6dca5b69e..9acc18a0cee 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -77,4 +77,22 @@ show tables; delete from mysql.user where user=_binary"test"; flush privileges; +# Test for bug #12517. +connect (con2,localhost,root,,test); +connection con2; +use test; +drop table if exists t1; +create table t1 (id integer not null auto_increment primary key); +drop table if exists t2; +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +disconnect con2; +sleep 5; +connect (con1,localhost,root,,test); +connection con1; +use test; +drop table if exists t2; +drop table if exists t1; + # End of 4.1 tests diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e845769d7ad..11b45b848c8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -353,12 +353,12 @@ void THD::cleanup(void) mysql_ha_flush(this, (TABLE_LIST*) 0, MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); hash_free(&handler_tables_hash); + delete_dynamic(&user_var_events); + hash_free(&user_vars); close_temporary_tables(this); my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); - delete_dynamic(&user_var_events); - hash_free(&user_vars); if (global_read_lock) unlock_global_read_lock(this); if (ull) From d02ec2b5d9ba03c53d35b54d15091815efe63aac Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 31 Aug 2005 14:04:54 +0500 Subject: [PATCH 04/48] Bug#12611: ESCAPE + LIKE do not work when the escape char is a multibyte one item_cmpfunc.cc: Pass unicode value as "escape" argument to my_wildcmp if a multibyte character set is used. For single byte character set nothing has changed: native (non-unicode) character code is still passed. ctype_utf8.result, ctype_utf8.test: adding test case sql/item_cmpfunc.cc: Bug#12611: ESCAPE + LIKE do not work when the escape char is a multibyte one Pass unicode code instead of native code as "escape" argument to my_wildcmp. mysql-test/t/ctype_utf8.test: adding test mysql-test/r/ctype_utf8.result: adding test --- mysql-test/r/ctype_utf8.result | 4 ++++ mysql-test/t/ctype_utf8.test | 6 ++++++ sql/item_cmpfunc.cc | 20 +++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 748361d3178..9f2d7eac700 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -955,6 +955,10 @@ char_length(a) length(a) a 2 4 ан drop table t1; set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; +'andre%' like 'andreñ%' escape 'ñ' +1 +set names utf8; select 'a\\' like 'a\\'; 'a\\' like 'a\\' 1 diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index e6342777839..0cdda648899 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -810,6 +810,12 @@ alter table t1 modify a char(2) character set utf8; select char_length(a), length(a), a from t1 order by a; drop table t1; +# +# Bugs#12611 +# ESCAPE + LIKE do not work when the escape char is a multibyte one +# +set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; # # Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0 diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9146b3c3b9e..c869e7f5c65 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2293,7 +2293,25 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); - escape= escape_str ? *(escape_str->ptr()) : '\\'; + if (escape_str) + { + CHARSET_INFO *cs= cmp.cmp_collation.collation; + if (use_mb(cs)) + { + my_wc_t wc; + int rc= cs->cset->mb_wc(cs, &wc, + (const uchar*) escape_str->ptr(), + (const uchar*) escape_str->ptr() + + escape_str->length()); + escape= (int) (rc > 0 ? wc : '\\'); + } + else + { + escape= *(escape_str->ptr()); + } + } + else + escape= '\\'; /* We could also do boyer-more for non-const items, but as we would have to From eac727b55a31bb5f00fb988b000b022114d06df5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 19:09:20 +1000 Subject: [PATCH 05/48] BUG#11607 Incorrect error code returned on deletion Save error on first failure. At end of execute, if the current error is 4350 (transaction already aborted), restore the original error (if there was one). ndb/src/ndbapi/NdbConnection.cpp: In NdbConnection::execute - returning 4350 instead of correct error. Save error on first failure. At end of execute, if the current error is 4350 (transaction already aborted), restore the original error (if there was one). --- ndb/src/ndbapi/NdbConnection.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index e1f70160fb7..c9e26f8ccaf 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -280,6 +280,7 @@ NdbConnection::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { + NdbError savedError= theError; DBUG_ENTER("NdbConnection::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); @@ -309,7 +310,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tPrepOp->theBlobList; while (tBlob != NULL) { if (tBlob->preExecute(tExecType, batch) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } if (batch) { @@ -338,7 +343,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tOp->theBlobList; while (tBlob != NULL) { if (tBlob->preCommit() == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -360,7 +369,12 @@ NdbConnection::execute(ExecType aTypeOfExec, } if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } + #ifdef ndb_api_crash_on_complex_blob_abort assert(theFirstOpInList == NULL && theLastOpInList == NULL); #else @@ -375,7 +389,11 @@ NdbConnection::execute(ExecType aTypeOfExec, while (tBlob != NULL) { // may add new operations if batch if (tBlob->postExecute(tExecType) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -406,6 +424,10 @@ NdbConnection::execute(ExecType aTypeOfExec, ndbout << "completed ops: " << n << endl; } #endif + + if(savedError.code!=0 && theError.code==4350) // Trans already aborted + theError= savedError; + DBUG_RETURN(ret); } From c66167d4472834ea2b6afec204c26e37c99dac97 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 2 Sep 2005 22:52:52 +0200 Subject: [PATCH 06/48] fix for BUG#12958 : mysqlimport with -L option crashing on HP-UX --- client/mysqlimport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 24392fedc1f..4bf4974748b 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object, const char *statement); static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0, - replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0, + replace=0,silent=0,ignore=0,opt_compress=0, opt_low_priority= 0, tty_password= 0; +static uint opt_local_file=0; static MYSQL mysql_connection; static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, From d96cf23c9a64adaf823b45cf0a0ff0e39babbe88 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 4 Sep 2005 21:00:00 +0500 Subject: [PATCH 07/48] Fix for bug #12938 (decimal arithmetic in the loop fails) mysql-test/r/type_newdecimal.result: test result fixed mysql-test/t/type_newdecimal.test: test case added strings/decimal.c: code to cut heading zeroes off the result of the multiplication added --- mysql-test/r/type_newdecimal.result | 32 +++++++++++++++++++++++++++++ mysql-test/t/type_newdecimal.test | 22 ++++++++++++++++++++ strings/decimal.c | 16 ++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 4980e2a73d2..f06e290a49b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -984,3 +984,35 @@ t1 CREATE TABLE `t1` ( `f1` decimal(10,0) unsigned zerofill NOT NULL default '0000000000' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +drop procedure if exists wg2; +Warnings: +Note 1305 PROCEDURE wg2 does not exist +create procedure wg2() +begin +declare v int default 1; +declare tdec decimal(5) default 0; +while v <= 9 do set tdec =tdec * 10; +select v, tdec; +set v = v + 1; +end while; +end// +call wg2()// +v tdec +1 0 +v tdec +2 0 +v tdec +3 0 +v tdec +4 0 +v tdec +5 0 +v tdec +6 0 +v tdec +7 0 +v tdec +8 0 +v tdec +9 0 +drop procedure wg2; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index f3be64506c7..55e0618a3e5 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1015,3 +1015,25 @@ create table t1 ( f1 decimal (0,0) zerofill not null default 0); show create table t1; drop table t1; + +# +# Bug 12938 (arithmetic loop's zero) +# +--disable-warnings +drop procedure if exists wg2; +--enable-warnings +delimiter //; +create procedure wg2() +begin + declare v int default 1; + declare tdec decimal(5) default 0; + while v <= 9 do set tdec =tdec * 10; + select v, tdec; + set v = v + 1; + end while; +end// + +call wg2()// + +delimiter ;// +drop procedure wg2; diff --git a/strings/decimal.c b/strings/decimal.c index 4dc5fa91e0a..7816f340eef 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1933,7 +1933,7 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), intg0=ROUND_UP(from1->intg+from2->intg), - frac0=frac1+frac2, error, i, j; + frac0=frac1+frac2, error, i, j, d_to_move; dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0, *start2, *stop2, *stop1, *start0, carry; @@ -2007,6 +2007,20 @@ int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) } } } + buf1= to->buf; + d_to_move= intg0 + ROUND_UP(to->frac); + while (!*buf1 && (to->intg > DIG_PER_DEC1)) + { + buf1++; + to->intg-= DIG_PER_DEC1; + d_to_move--; + } + if (to->buf < buf1) + { + dec1 *cur_d= to->buf; + for (; d_to_move; d_to_move--, cur_d++, buf1++) + *cur_d= *buf1; + } return error; } From e254105bec21fc101326ca366ef85cd0d8d4ed98 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 14:48:18 +0500 Subject: [PATCH 08/48] item_cmpfunc.h: Bug 12611 : ESCAPE + LIKE do not work when the escape char is a multibyte one Forgot to commit this file in the previous changeset, together with other files. sql/item_cmpfunc.h: Bug 12611 : ESCAPE + LIKE do not work when the escape char is a multibyte one Forgot to commit this file in the previous changeset, together with other files. --- sql/item_cmpfunc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..697b26bb1ae 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -879,7 +879,7 @@ class Item_func_like :public Item_bool_func2 Item *escape_item; public: - char escape; + int escape; Item_func_like(Item *a,Item *b, Item *escape_arg) :Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), From 965afd45a18f0af3395c4750c072788e1f9b2ee1 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 16:16:10 +0500 Subject: [PATCH 09/48] func_like.result, func_like.test: adding test case. item_cmpfunc.cc: Bug#12611 ESCAPE + LIKE do not work when the escape char is a multibyte one Additional fix for 8bit character sets: escape character must be converted into operation character set. sql/item_cmpfunc.cc: Bug#12611 ESCAPE + LIKE do not work when the escape char is a multibyte one Additional fix for 8bit character sets: escape character must be converted into operation character set. mysql-test/t/func_like.test: adding test case. mysql-test/r/func_like.result: adding test case. --- mysql-test/r/func_like.result | 7 +++++++ mysql-test/t/func_like.test | 17 +++++++++++++++++ sql/item_cmpfunc.cc | 19 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index a58432cb06e..bc658f9f7de 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -158,3 +158,10 @@ DROP TABLE t1; select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin 1 +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; +'andre%' like 'andreÊ%' escape 'Ê' +1 +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; +_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' +1 diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 684d7032038..4e1183afeff 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -96,4 +96,21 @@ DROP TABLE t1; # select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +# +# Check 8bit escape character +# +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; + +# Check 8bit escape character with charset conversion: +# For "a LIKE b ESCAPE c" expressions, +# escape character is converted into the operation character set, +# which is result of aggregation of character sets of "a" and "b". +# "c" itself doesn't take part in aggregation, because its collation +# doesn't matter, escape character is always compared binary. +# In the example below, escape character is converted from koi8r into cp1251: +# +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; + +# # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c869e7f5c65..ead07892bee 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2307,7 +2307,24 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) } else { - escape= *(escape_str->ptr()); + /* + In the case of 8bit character set, we pass native + code instead of Unicode code as "escape" argument. + Convert to "cs" if charset of escape differs. + */ + uint32 unused; + if (escape_str->needs_conversion(escape_str->length(), + escape_str->charset(), cs, &unused)) + { + char ch; + uint errors; + uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(), + escape_str->length(), + escape_str->charset(), &errors); + escape= cnvlen ? ch : '\\'; + } + else + escape= *(escape_str->ptr()); } } else From f1cc5049810a0bcf701fe994aa3c4f6c5bbae8ab Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 18:03:08 +0400 Subject: [PATCH 10/48] item_cmpfunc.h: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The classes Item_func_between, Item_func_if, Item_func_in are modified. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. The class Item_func_opt_neg is added to factor out the functionality common for the modified classes Item_func_between and Item_func_in. item_cmpfunc.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Added Item_func_between::fix_fields(), Item_func_if::fix_fields(), Item_func_in::fix_fields(). They correct generic calculation of the not_null_tables attribute when it is needed. Modified Item_func_between::val_int(), Item_func_in::val_int(). opt_range.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The function get_mm_tree() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql_yacc.yy: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions. join_outer.result: Fixed some testcases results (bugs #12101, #12102) join_outer.test: Added testcases for bugs #12101, #12102 mysql-test/t/join_outer.test: Added testcases for bugs #12101, #12102 mysql-test/r/join_outer.result: Fixed some testcases results (bugs #12101, #12102) sql/sql_yacc.yy: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expresions. sql/opt_range.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The function get_mm_tree() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/item_cmpfunc.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. Added Item_func_between::fix_fields(), Item_func_if::fix_fields(), Item_func_in::fix_fields(). They correct generic calculation of the not_null_tables attribute when it is needed. Modified Item_func_between::val_int(), Item_func_in::val_int(). sql/item_cmpfunc.h: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions. The classes Item_func_between, Item_func_if, Item_func_in are modified. Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. The class Item_func_opt_neg is added to factor out the functionality common for the modified classes Item_func_between and Item_func_in. --- mysql-test/r/join_outer.result | 133 +++++++++++++++++++++++++++ mysql-test/t/join_outer.test | 46 ++++++++++ sql/item_cmpfunc.cc | 158 +++++++++++++++++++++++++++++++-- sql/item_cmpfunc.h | 55 ++++++++---- sql/opt_range.cc | 5 +- sql/sql_yacc.yy | 32 +++++-- 6 files changed, 397 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index b6265aac4a3..d5ae1a58e83 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -883,3 +883,136 @@ Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() drop table t1, t2; set group_concat_max_len=default; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +DROP TABLE t1,t2; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index fa2dd93c9ba..05cd2fb152e 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -625,4 +625,50 @@ select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; drop table t1, t2; set group_concat_max_len=default; +# +# Test for bugs +# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN +# #12102: erroneously missing outer join elimination in case of WHERE IN/IF +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); + +DROP TABLE t1,t2; + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9146b3c3b9e..99ca0df355b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -820,6 +820,54 @@ longlong Item_func_interval::val_int() return i-1; } + +/* + Perform context analysis of a BETWEEN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_between as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2)) + T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_between::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) +{ + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ + if (pred_level && !negated) + return 0; + + /* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */ + not_null_tables_cache= args[0]->not_null_tables() | + (args[1]->not_null_tables() & args[2]->not_null_tables()); + + return 0; +} + + void Item_func_between::fix_length_and_dec() { max_length= 1; @@ -871,8 +919,9 @@ longlong Item_func_between::val_int() a=args[1]->val_str(&value1); b=args[2]->val_str(&value2); if (!args[1]->null_value && !args[2]->null_value) - return (sortcmp(value,a,cmp_collation.collation) >= 0 && - sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0; + return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && + sortcmp(value,b,cmp_collation.collation) <= 0) != + negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -894,7 +943,7 @@ longlong Item_func_between::val_int() a=args[1]->val_int(); b=args[2]->val_int(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -914,7 +963,7 @@ longlong Item_func_between::val_int() a=args[1]->val(); b=args[2]->val(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -926,7 +975,7 @@ longlong Item_func_between::val_int() null_value= value >= a; } } - return 0; + return (longlong) (!null_value && negated); } @@ -1019,6 +1068,49 @@ Item_func_ifnull::val_str(String *str) } +/* + Perform context analysis of an IF item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_if as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(IF(e,e1,e2) = T1(IF(e,e1,e2)) + T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2)) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_if::fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + args[0]->top_level_item(); + + if (Item_func::fix_fields(thd, tlist, ref)) + return 1; + + not_null_tables_cache= (args[1]->not_null_tables() + & args[2]->not_null_tables()); + + return 0; +} + + void Item_func_if::fix_length_and_dec() { @@ -1750,6 +1842,56 @@ bool Item_func_in::nulls_in_row() } +/* + Perform context analysis of an IN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_in as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei))) + T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_in::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + Item **arg, **arg_end; + + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ + if (pred_level && negated) + return 0; + + /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */ + not_null_tables_cache= ~(table_map) 0; + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++) + not_null_tables_cache&= (*arg)->not_null_tables(); + not_null_tables_cache|= (*args)->not_null_tables(); + return 0; +} + + static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, @@ -1840,7 +1982,7 @@ longlong Item_func_in::val_int() { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); - return tmp; + return (longlong) (!null_value && tmp != negated); } in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) @@ -1849,11 +1991,11 @@ longlong Item_func_in::val_int() for (uint i=1 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) - return 1; // Would maybe be nice with i ? + return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; - return 0; + return (longlong) (!null_value && negated); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..2ebf794f0a8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -358,17 +358,49 @@ public: }; -class Item_func_between :public Item_int_func +/* + The class Item_func_opt_neg is defined to factor out the functionality + common for the classes Item_func_between and Item_func_in. The objects + of these classes can express predicates or there negations. + The alternative approach would be to create pairs Item_func_between, + Item_func_notbetween and Item_func_in, Item_func_notin. + +*/ + +class Item_func_opt_neg :public Item_int_func +{ +public: + bool negated; /* <=> the item represents NOT */ + bool pred_level; /* <=> [NOT] is used on a predicate level */ +public: + Item_func_opt_neg(Item *a, Item *b, Item *c) + :Item_int_func(a, b, c), negated(0), pred_level(0) {} + Item_func_opt_neg(List &list) + :Item_int_func(list), negated(0), pred_level(0) {} +public: + inline void negate() { negated= !negated; } + inline void top_level_item() { pred_level= 1; } + Item *neg_transformer(THD *thd) + { + negated= !negated; + return this; + } +}; + + +class Item_func_between :public Item_func_opt_neg { DTCollation cmp_collation; public: Item_result cmp_type; String value0,value1,value2; - Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} + Item_func_between(Item *a, Item *b, Item *c) + :Item_func_opt_neg(a, b, c) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void print(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -433,15 +465,9 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) - { - DBUG_ASSERT(fixed == 0); - args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); - } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); const char *func_name() const { return "if"; } - table_map not_null_tables() const { return 0; } }; @@ -736,7 +762,7 @@ public: } }; -class Item_func_in :public Item_int_func +class Item_func_in :public Item_func_opt_neg { Item_result cmp_type; in_vector *array; @@ -745,11 +771,12 @@ class Item_func_in :public Item_int_func DTCollation cmp_collation; public: Item_func_in(List &list) - :Item_int_func(list), array(0), in_item(0), have_null(0) + :Item_func_opt_neg(list), array(0), in_item(0), have_null(0) { allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void cleanup() { @@ -769,12 +796,6 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } - /* - IN() protect from NULL only first argument, if construction like - "expression IN ()" will be allowed, we will need to check number of - argument here, because "NOT(NULL IN ())" is TRUE. - */ - table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2dd097cbaab..5cb330100f8 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -849,7 +849,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::BETWEEN) { - if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) + if (!((Item_func_between *)(cond_func))->negated && + cond_func->arguments()[0]->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (cond_func->arguments()[0]))->field; Item_result cmp_type=field->cmp_type(); @@ -866,7 +867,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::IN_FUNC) { // COND OR Item_func_in *func=(Item_func_in*) cond_func; - if (func->key_item()->type() == Item::FIELD_ITEM) + if (!func->negated && func->key_item()->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (func->key_item()))->field; Item_result cmp_type=field->cmp_type(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index be8ead8e157..6283cad7cc8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2598,7 +2598,12 @@ expr_expr: expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | expr NOT IN_SYM in_subselect @@ -2608,7 +2613,11 @@ expr_expr: | expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2656,7 +2665,11 @@ no_in_expr: no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2704,7 +2717,12 @@ no_and_expr: no_and_expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | no_and_expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | no_and_expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | no_and_expr NOT IN_SYM in_subselect @@ -2714,7 +2732,11 @@ no_and_expr: | no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } From d877cdf3e7fa6c176a2dea418deaa0bb2d9500ff Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Sep 2005 22:20:11 -0700 Subject: [PATCH 11/48] func_gconcat.result, func_gconcat.test: Added test cases for bug #12863. item_sum.cc, item_sum.h: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. sql/item_sum.h: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. sql/item_sum.cc: Fixed bug #12863. Added a flag to Item_func_group_concat set to FALSE after concatenation of the first element of a group. mysql-test/t/func_gconcat.test: Added test cases for bug #12863. mysql-test/r/func_gconcat.result: Added test cases for bug #12863. --- mysql-test/r/func_gconcat.result | 20 ++++++++++++++++++++ mysql-test/t/func_gconcat.test | 16 ++++++++++++++++ sql/item_sum.cc | 8 +++++--- sql/item_sum.h | 1 + 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 12bc5ca2582..9c0c05ae296 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -560,3 +560,23 @@ group_concat('x') NULL 1 drop table t1; +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES +(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +,,x,y,z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; +GROUP_CONCAT(a ORDER BY a) +,,,x,y,z +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +GROUP_CONCAT(a) +,y +,x +z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; +GROUP_CONCAT(a ORDER BY a) +,y +,x +,z +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 9e003d19ab9..aa8ce0f4bdc 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -356,4 +356,20 @@ select * from (select group_concat(a) from t1) t2; select group_concat('x') UNION ALL select 1; drop table t1; +# +# Bug #12863 : missing separators after first empty cancatanated elements +# + +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES + (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); + +SELECT GROUP_CONCAT(a) FROM t1; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; + +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 000dcdb4997..7f13fdf82b2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1664,7 +1664,9 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), char buff[MAX_FIELD_WIDTH]; String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2; - if (item->result.length()) + if (item->no_appended) + item->no_appended= FALSE; + else item->result.append(*item->separator); tmp.length(0); @@ -1856,6 +1858,7 @@ void Item_func_group_concat::clear() result.copy(); null_value= TRUE; warning_for_row= FALSE; + no_appended= TRUE; if (tree_mode) reset_tree(tree); } @@ -1898,8 +1901,7 @@ bool Item_func_group_concat::add() void Item_func_group_concat::reset_field() { - if (tree_mode) - reset_tree(tree); + DBUG_ASSERT(0); } diff --git a/sql/item_sum.h b/sql/item_sum.h index a3b422565d1..d53d8d861ae 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -709,6 +709,7 @@ class Item_func_group_concat : public Item_sum uint arg_count_field; uint field_list_offset; uint count_cut_values; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) From a777907a51510cec8ab4a502d0924e072b47665d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 15:38:09 +0500 Subject: [PATCH 12/48] Fix for bug#11775 Variable character_set_system does not exist (sometimes). Variable character_set_system is selectable now More accurate error message results during update of character_set_system and some other read only variables mysql-test/r/variables.result: Fix for bug#11775 Variable character_set_system does not exist (sometimes). test case mysql-test/t/variables.test: Fix for bug#11775 Variable character_set_system does not exist (sometimes). test case --- mysql-test/r/variables.result | 7 +++++++ mysql-test/t/variables.test | 9 +++++++++ sql/set_var.cc | 29 +++-------------------------- sql/set_var.h | 3 ++- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index a5b76c03b29..265f353ae3c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -545,3 +545,10 @@ select @@max_heap_table_size > 0; select @@have_innodb; @@have_innodb # +select @@character_set_system; +@@character_set_system +utf8 +set global character_set_system = latin1; +ERROR HY000: Variable 'character_set_system' is a read only variable +set @@global.version_compile_os='234'; +ERROR HY000: Variable 'version_compile_os' is a read only variable diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 372e865467e..afd0fe23805 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -435,3 +435,12 @@ select @@max_heap_table_size > 0; --replace_column 1 # select @@have_innodb; + +# +# Bug #11775 Variable character_set_system does not exist (sometimes) +# +select @@character_set_system; +--error 1238 +set global character_set_system = latin1; +--error 1238 +set @@global.version_compile_os='234'; diff --git a/sql/set_var.cc b/sql/set_var.cc index ea4c08cea27..774062dedf2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -142,11 +142,8 @@ sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", &SV::bulk_insert_buff_size); sys_var_character_set_server sys_character_set_server("character_set_server"); -sys_var_str sys_charset_system("character_set_system", - sys_check_charset, - sys_update_charset, - sys_set_default_charset, - (char *)my_charset_utf8_general_ci.name); +sys_var_const_str sys_charset_system("character_set_system", + (char *)my_charset_utf8_general_ci.name); sys_var_character_set_database sys_character_set_database("character_set_database"); sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); @@ -569,6 +566,7 @@ sys_var *sys_variables[]= &sys_character_set_client, &sys_character_set_connection, &sys_character_set_results, + &sys_charset_system, &sys_collation_connection, &sys_collation_database, &sys_collation_server, @@ -1117,27 +1115,6 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type) sizeof(ft_boolean_syntax)-1); } -/* - The following 3 functions need to be changed in 4.1 when we allow - one to change character sets -*/ - -static int sys_check_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static bool sys_update_charset(THD *thd, set_var *var) -{ - return 0; -} - - -static void sys_set_default_charset(THD *thd, enum_var_type type) -{ -} - /* If one sets the LOW_PRIORIY UPDATES flag, we also must change the diff --git a/sql/set_var.h b/sql/set_var.h index c8b075ddd35..40ff4c8583f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -190,6 +190,7 @@ public: return 1; } bool check_default(enum_var_type type) { return 1; } + bool is_readonly() const { return 1; } }; @@ -900,7 +901,7 @@ int sql_set_variables(THD *thd, List *var_list); bool not_all_support_one_shot(List *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); ulong fix_sql_mode(ulong sql_mode); -extern sys_var_str sys_charset_system; +extern sys_var_const_str sys_charset_system; extern sys_var_str sys_init_connect; extern sys_var_str sys_init_slave; extern sys_var_thd_time_zone sys_time_zone; From e6438062db34d3daa40cc97b164826146d69fbf8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 12:49:11 +0200 Subject: [PATCH 13/48] Modified ndb log message on startup failure --- ndb/src/kernel/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index aa220b0ae05..d9953b920d2 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -394,5 +394,5 @@ handler_sigusr1(int signum) failed_startups++; failed_startup_flag = true; } - g_eventLogger.info("Received signal %d. Ndbd failed startup (%u).", signum, failed_startups); + g_eventLogger.info("Angel received ndbd startup failure count %u.", failed_startups); } From 48c3c329b3916ef6a710d5221b8bd4671817fd3c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 16:11:53 +0500 Subject: [PATCH 14/48] Fix for bug#12905 show fields from view behaving erratically with current database use saved view db name in case of view --- mysql-test/r/information_schema.result | 11 +++++++++++ mysql-test/t/information_schema.test | 14 +++++++++++++- sql/sql_show.cc | 21 +++++++++++++++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 20b2f12f0a8..9a7a0b48f47 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -979,3 +979,14 @@ WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # NULL latin1_swedish_ci NULL +DROP TABLE t1,t2; +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +select database(); +database() +NULL +show fields from test.v1; +Field Type Null Key Default Extra +c int(11) YES NULL +drop view v1; +drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 6be193e0e0c..aa1b632f919 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -665,4 +665,16 @@ SHOW TABLE STATUS FROM test WHERE name IN ( SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_TYPE='BASE TABLE'); -DROP TABLE t1,t2 +DROP TABLE t1,t2; + +# +# Bug #12905 show fields from view behaving erratically with current database +# +create table t1(f1 int); +create view v1 (c) as select f1 from t1; +connect (con5,localhost,root,,*NO-ONE*); +select database(); +show fields from test.v1; +connection default; +drop view v1; +drop table t1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bc3c8fbdc5d..51330a6109b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1988,10 +1988,20 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() + + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case(this part of code is used only for + 'show columns' & 'show statistics' commands). */ error= test(schema_table->process_table(thd, show_table_list, - table, res, show_table_list->db, - show_table_list->alias)); + table, res, + (show_table_list->view ? + show_table_list->view_db.str : + show_table_list->db), + show_table_list->alias)); close_thread_tables(thd); show_table_list->table= 0; goto err; @@ -2092,6 +2102,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->derived_tables= 0; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + /* + We should use show_table_list->alias instead of + show_table_list->table_name because table_name + could be changed during opening of I_S tables. It's safe + to use alias because alias contains original table name + in this case. + */ res= schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias); From 0a61c3abda74efa51bf697dfcaa16d80ff874fcd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 17:42:47 +0400 Subject: [PATCH 15/48] join_outer.result, opt_range.cc, item_cmpfunc.cc: Post merge changes sql_yacc.yy: Post merge changes sql_select.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions (post merge changes). The function add_key_fields() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/item_cmpfunc.cc: Post merge changes sql/opt_range.cc: Post merge changes sql/sql_select.cc: Fixed bugs #12101, #12102: wrong calculation of not_null_tables() for some expressions (post merge changes). The function add_key_fields() is modified. There cannot be NOT before BETWEEN/IN anymore. Rather Item_func_between/in objects can represent now [NOT]BETWEEN/IN expressions. sql/sql_yacc.yy: Post merge changes. mysql-test/r/join_outer.result: Post merge changes --- mysql-test/r/join_outer.result | 10 +++++----- sql/item_cmpfunc.cc | 16 ++++++++-------- sql/opt_range.cc | 16 ++++------------ sql/sql_select.cc | 13 ------------- sql/sql_yacc.yy | 16 ++++++++-------- 5 files changed, 25 insertions(+), 46 deletions(-) diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 6295356b800..92b352aa608 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1123,14 +1123,14 @@ a b a b 7 8 7 5 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 DROP TABLE t1,t2; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 46284c422c2..dfdc7319d4d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1018,9 +1018,9 @@ longlong Item_func_interval::val_int() */ bool -Item_func_between::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) +Item_func_between::fix_fields(THD *thd, Item **ref) { - if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + if (Item_func_opt_neg::fix_fields(thd, ref)) return 1; /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ @@ -1132,8 +1132,8 @@ longlong Item_func_between::val_int() a_dec= args[1]->val_decimal(&a_buf); b_dec= args[2]->val_decimal(&b_buf); if (!args[1]->null_value && !args[2]->null_value) - return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0); - + return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 && + my_decimal_cmp(dec, b_dec) <= 0) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -1320,12 +1320,12 @@ Item_func_ifnull::str_op(String *str) */ bool -Item_func_if::fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) +Item_func_if::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); args[0]->top_level_item(); - if (Item_func::fix_fields(thd, tlist, ref)) + if (Item_func::fix_fields(thd, ref)) return 1; not_null_tables_cache= (args[1]->not_null_tables() @@ -2305,11 +2305,11 @@ bool Item_func_in::nulls_in_row() */ bool -Item_func_in::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_in::fix_fields(THD *thd, Item **ref) { Item **arg, **arg_end; - if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + if (Item_func_opt_neg::fix_fields(thd, ref)) return 1; /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ecf4b5de1cb..cb250251155 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3524,20 +3524,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) } Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - /* Optimize NOT BETWEEN and NOT IN */ - Item *arg= cond_func->arguments()[0]; - if (arg->type() != Item::FUNC_ITEM) - DBUG_RETURN(0); - cond_func= (Item_func*) arg; - if (cond_func->functype() != Item_func::BETWEEN && - cond_func->functype() != Item_func::IN_FUNC) - DBUG_RETURN(0); - inv= TRUE; - } + if (cond_func->functype() == Item_func::BETWEEN || + cond_func->functype() == Item_func::IN_FUNC) + inv= ((Item_func_opt_neg *) cond_func)->negated; else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); + param->cond= cond; switch (cond_func->functype()) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0de06ea395a..83a4cd4bbf3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2862,19 +2862,6 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, if (cond->type() != Item::FUNC_ITEM) return; Item_func *cond_func= (Item_func*) cond; - if (cond_func->functype() == Item_func::NOT_FUNC) - { - Item *item= cond_func->arguments()[0]; - /* - At this moment all NOT before simple comparison predicates - are eliminated. NOT IN and NOT BETWEEN are treated similar - IN and BETWEEN respectively. - */ - if (item->type() == Item::FUNC_ITEM && - ((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY) - add_key_fields(key_fields,and_level,item,usable_tables); - return; - } switch (cond_func->select_optimize()) { case Item_func::OPTIMIZE_NONE: break; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8723c558df3..ad1fd68ddcd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4274,7 +4274,9 @@ predicate: else { $5->push_front($1); - $$= negate_expression(YYTHD, new Item_func_in(*$5)); + Item_func_in *item = new Item_func_in(*$5); + item->negate(); + $$= item; } } | bit_expr IN_SYM in_subselect @@ -4284,7 +4286,11 @@ predicate: | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate { $$= new Item_func_between($1,$3,$5); } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate - { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } @@ -4350,12 +4356,6 @@ all_or_any: ALL { $$ = 1; } | ANY_SYM { $$ = 0; } ; - - - - - - interval_expr: INTERVAL_SYM expr { $$=$2; } ; From fe5a4e3be714869a15d6acfb836edeb7983c0ac2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 17:04:22 +0200 Subject: [PATCH 16/48] Bug #12987 yassl: Compilation of integer.cpp fails on OS X Tiger extra/yassl/taocrypt/include/misc.hpp: Disable X86ASM on OsX --- extra/yassl/taocrypt/include/misc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/yassl/taocrypt/include/misc.hpp b/extra/yassl/taocrypt/include/misc.hpp index 5a31510911e..f705cc99970 100644 --- a/extra/yassl/taocrypt/include/misc.hpp +++ b/extra/yassl/taocrypt/include/misc.hpp @@ -91,7 +91,7 @@ public: // no gas on these systems ?, disable for now -#if defined(__sun__) || defined (__QNX__) +#if defined(__sun__) || defined (__QNX__) || defined (__APPLE__) #define TAOCRYPT_DISABLE_X86ASM #endif From eb769e54b8ab429cb86502866d438a44fcee7473 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 19:39:47 +0400 Subject: [PATCH 17/48] Fix for BUG#12637: Make SPs+user variables replication work: * Allocate thd->user_var_events elements on appropriate mem_root * If several SP statements are binlogged as a single statement, collect all user var accesses they make (grep for StoredRoutinesBinlogging for details) mysql-test/r/rpl_sp_effects.result: Testcase for BUG#12637 mysql-test/r/sp.result: re-enabled test case for BUG#12297 mysql-test/t/rpl_sp_effects.test: Testcase for BUG#12637 mysql-test/t/sp.test: re-enabled test case for BUG#12297 sql/item_func.cc: Fix for BUG#12637: Make SPs+user variables replication work: * Allocate thd->user_var_events elements on appropriate mem_root * If several SP statements are binlogged as a single statement, collect all user var accesses they make. sql/log.cc: Fix for BUG#12637: Make SPs+user variables replication work: * Allocate thd->user_var_events elements on appropriate mem_root * If several SP statements are binlogged as a single statement, collect all user var accesses they make. sql/sp_head.cc: Fix for BUG#12637: Make SPs+user variables replication work: * Allocate thd->user_var_events elements on appropriate mem_root * If several SP statements are binlogged as a single statement, collect all user var accesses they make. sql/sp_head.h: Remove compiler warning. sql/sql_class.h: Fix for BUG#12637: Make SPs+user variables replication work. sql/sql_parse.cc: Fix for BUG#12637: Make SPs+user variables replication work. --- mysql-test/r/rpl_sp_effects.result | 57 ++++++++++++++++++++++++++++++ mysql-test/r/sp.result | 13 +++++++ mysql-test/t/rpl_sp_effects.test | 48 +++++++++++++++++++++++++ mysql-test/t/sp.test | 32 +++++++---------- sql/item_func.cc | 15 +++++--- sql/log.cc | 7 ++++ sql/sp_head.cc | 48 +++++++++++++++++++------ sql/sp_head.h | 5 +-- sql/sql_class.h | 12 +++++-- sql/sql_parse.cc | 3 ++ 10 files changed, 203 insertions(+), 37 deletions(-) diff --git a/mysql-test/r/rpl_sp_effects.result b/mysql-test/r/rpl_sp_effects.result index 8bcbf1a60d0..bf8128d9385 100644 --- a/mysql-test/r/rpl_sp_effects.result +++ b/mysql-test/r/rpl_sp_effects.result @@ -156,3 +156,60 @@ slave: 6 drop procedure p1; drop function f1; drop table t1,t2; +create table t1 (a int); +create procedure p1() +begin +insert into t1 values(@x); +set @x=@x+1; +insert into t1 values(@x); +if (f2()) then +insert into t1 values(1243); +end if; +end// +create function f2() returns int +begin +insert into t1 values(@z); +set @z=@z+1; +insert into t1 values(@z); +return 0; +end// +create function f1() returns int +begin +insert into t1 values(@y); +call p1(); +return 0; +end// +set @x=10; +set @y=20; +set @z=100; +select f1(); +f1() +0 +set @x=30; +call p1(); +select 'master', a from t1; +master a +master 20 +master 10 +master 11 +master 100 +master 101 +master 30 +master 31 +master 101 +master 102 +select 'slave', a from t1; +slave a +slave 20 +slave 10 +slave 11 +slave 100 +slave 101 +slave 30 +slave 31 +slave 101 +slave 102 +drop table t1; +drop function f1; +drop function f2; +drop procedure p1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4424f4e6ad4..5199377fbd1 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3085,6 +3085,19 @@ column_name bug10055(t.column_name) id id data data drop function bug10055| +drop procedure if exists bug12297| +create procedure bug12297(lim int) +begin +set @x = 0; +repeat +insert into t1(id,data) +values('aa', @x); +set @x = @x + 1; +until @x >= lim +end repeat; +end| +call bug12297(10)| +drop procedure bug12297| drop function if exists f_bug11247| drop procedure if exists p_bug11247| create function f_bug11247(param int) diff --git a/mysql-test/t/rpl_sp_effects.test b/mysql-test/t/rpl_sp_effects.test index f8e83eabe90..9da5723b993 100644 --- a/mysql-test/t/rpl_sp_effects.test +++ b/mysql-test/t/rpl_sp_effects.test @@ -152,4 +152,52 @@ drop procedure p1; drop function f1; drop table t1,t2; +# BUG#12637: User variables + SPs replication +create table t1 (a int); +delimiter //; +create procedure p1() +begin + insert into t1 values(@x); + set @x=@x+1; + insert into t1 values(@x); + if (f2()) then + insert into t1 values(1243); + end if; +end// + +create function f2() returns int +begin + insert into t1 values(@z); + set @z=@z+1; + insert into t1 values(@z); + return 0; +end// + +create function f1() returns int +begin + insert into t1 values(@y); + call p1(); + return 0; +end// + +delimiter ;// + +set @x=10; +set @y=20; +set @z=100; +select f1(); + +set @x=30; +call p1(); + +select 'master', a from t1; +sync_slave_with_master; +connection slave; +select 'slave', a from t1; + +connection master; +drop table t1; +drop function f1; +drop function f2; +drop procedure p1; sync_slave_with_master; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index d52ebbbbf67..add51e806c0 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3877,29 +3877,23 @@ drop function bug10055| # consumption by passing large input parameter. # -# -# Note: the test is currenly disabled because of the -# Bug #12637: SP crashes the server if it has update query with user var -# & binlog is enabled. -# - --disable_warnings -#drop procedure if exists bug12297| +drop procedure if exists bug12297| --enable_warnings -#create procedure bug12297(lim int) -#begin -# set @x = 0; -# repeat -# insert into t1(id,data) -# values('aa', @x); -# set @x = @x + 1; -# until @x >= lim -# end repeat; -#end| +create procedure bug12297(lim int) +begin + set @x = 0; + repeat + insert into t1(id,data) + values('aa', @x); + set @x = @x + 1; + until @x >= lim + end repeat; +end| -#call bug12297(10)| -#drop procedure bug12297| +call bug12297(10)| +drop procedure bug12297| # # Bug #11247 "Stored procedures: Function calls in long loops leak memory" diff --git a/sql/item_func.cc b/sql/item_func.cc index 22d9fbbad34..c9565801389 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3879,7 +3879,8 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command, if (!(var_entry= get_variable(&thd->user_vars, name, 0))) goto err; } - else if (var_entry->used_query_id == thd->query_id) + else if (var_entry->used_query_id == thd->query_id || + mysql_bin_log.is_query_in_union(thd, var_entry->used_query_id)) { /* If this variable was already stored in user_var_events by this query @@ -3896,10 +3897,16 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command, appears: > set @a:=1; > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); - We have to write to binlog value @a= 1; + We have to write to binlog value @a= 1. + + We allocate the user_var_event on user_var_events_alloc pool, not on + the this-statement-execution pool because in SPs user_var_event objects + may need to be valid after current [SP] statement execution pool is + destroyed. */ - size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; - if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size))) + size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; + if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) + alloc_root(thd->user_var_events_alloc, size))) goto err; user_var_event->value= (char*) user_var_event + diff --git a/sql/log.cc b/sql/log.cc index d62fa52a165..920a3fcff42 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1559,6 +1559,7 @@ void MYSQL_LOG::start_union_events(THD *thd) thd->binlog_evt_union.do_union= TRUE; thd->binlog_evt_union.unioned_events= FALSE; thd->binlog_evt_union.unioned_events_trans= FALSE; + thd->binlog_evt_union.first_query_id= thd->query_id; } void MYSQL_LOG::stop_union_events(THD *thd) @@ -1567,6 +1568,12 @@ void MYSQL_LOG::stop_union_events(THD *thd) thd->binlog_evt_union.do_union= FALSE; } +bool MYSQL_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) +{ + return (thd->binlog_evt_union.do_union && + query_id_param >= thd->binlog_evt_union.first_query_id); +} + /* Write an event to the binary log */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 14956138cbf..833a9209360 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -678,10 +678,35 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) * If this function invocation is done from a statement that is written into the binary log. * If there were any attempts to write events to the binary log during - function execution. + function execution (grep for start_union_events and stop_union_events) + If the answers are No and Yes, we write the function call into the binary log as "DO spfunc(, , ...)" + + + 4. Miscellaneous issues. + + 4.1 User variables. + When we call mysql_bin_log.write() for an SP statement, thd->user_var_events + must hold set<{var_name, value}> pairs for all user variables used during + the statement execution. + This set is produced by tracking user variable reads during statement + execution. + + Fo SPs, this has the following implications: + 1) thd->user_var_events may contain events from several SP statements and + needs to be valid after exection of these statements was finished. In + order to achieve that, we + * Allocate user_var_events array elements on appropriate mem_root (grep + for user_var_events_alloc). + * Use is_query_in_union() to determine if user_var_event is created. + + 2) We need to empty thd->user_var_events after we have wrote a function + call. This is currently done by making + reset_dynamic(&thd->user_var_events); + calls in several different places. (TODO cosider moving this into + mysql_bin_log.write() function) */ @@ -897,6 +922,7 @@ int sp_head::execute(THD *thd) /* Don't change NOW() in FUNCTION or TRIGGER */ if (!thd->in_sub_stmt) thd->set_time(); // Make current_time() et al work + /* We have to set thd->stmt_arena before executing the instruction to store in the instruction free_list all new items, created @@ -904,6 +930,13 @@ int sp_head::execute(THD *thd) items made during other permanent subquery transformations). */ thd->stmt_arena= i; + + /* will binlog this separately */ + if (thd->prelocked_mode == NON_PRELOCKED) //TODO: change to event union? + { + thd->user_var_events_alloc= thd->mem_root; + } + ret= i->execute(thd, &ip); /* @@ -918,15 +951,6 @@ int sp_head::execute(THD *thd) /* we should cleanup free_list and memroot, used by instruction */ thd->free_items(); - /* - FIXME: we must free user var events only if the routine is executed - in non-prelocked mode and statement-by-statement replication is used. - But if we don't free them now, the server crashes because user var - events are allocated in execute_mem_root. This is Bug#12637, and when - it's fixed, please add if (thd->options & OPTION_BIN_LOG) here. - */ - if (opt_bin_log) - reset_dynamic(&thd->user_var_events); free_root(&execute_mem_root, MYF(0)); /* @@ -1084,7 +1108,10 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) binlog_save_options= thd->options; need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); if (need_binlog_call) + { + reset_dynamic(&thd->user_var_events); mysql_bin_log.start_union_events(thd); + } thd->options&= ~OPTION_BIN_LOG; ret= execute(thd); @@ -1118,6 +1145,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) "Invoked ROUTINE modified a transactional table but MySQL " "failed to reflect this change in the binary log"); } + reset_dynamic(&thd->user_var_events); } if (m_type == TYPE_ENUM_FUNCTION && ret == 0) diff --git a/sql/sp_head.h b/sql/sp_head.h index 1c54b1a567d..271119ff2fb 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -108,13 +108,14 @@ class sp_head :private Query_arena MEM_ROOT main_mem_root; public: /* Possible values of m_flags */ - const static int + enum { HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN IN_SIMPLE_CASE= 2, // Is set if parsing a simple CASE IN_HANDLER= 4, // Is set if the parser is in a handler body MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE - IS_INVOKED= 32; // Is set if this sp_head is being used. + IS_INVOKED= 32 // Is set if this sp_head is being used. + }; int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE uint m_flags; // Boolean attributes of a stored routine diff --git a/sql/sql_class.h b/sql/sql_class.h index b7073ecf5c5..a0c61944c6a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -313,6 +313,7 @@ public: void start_union_events(THD *thd); void stop_union_events(THD *thd); + bool is_query_in_union(THD *thd, query_id_t query_id_param); /* v stands for vector @@ -1303,8 +1304,9 @@ public: /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; enum_check_fields count_cuted_fields; - /* for user variables replication*/ - DYNAMIC_ARRAY user_var_events; + + DYNAMIC_ARRAY user_var_events; /* For user variables replication */ + MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */ enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED }; killed_state volatile killed; @@ -1366,6 +1368,12 @@ public: mysql_bin_log.start_union_events() call. */ bool unioned_events_trans; + + /* + 'queries' (actually SP statements) that run under inside this binlog + union have thd->query_id >= first_query_id. + */ + query_id_t first_query_id; } binlog_evt_union; THD(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e3f9c0dc148..31582e7b2f4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5162,7 +5162,10 @@ void mysql_reset_thd_for_next_command(THD *thd) if (!thd->in_sub_stmt) { if (opt_bin_log) + { reset_dynamic(&thd->user_var_events); + thd->user_var_events_alloc= thd->mem_root; + } thd->clear_error(); thd->total_warn_count=0; // Warnings for this query thd->rand_used= 0; From a3fbfc037d83a58704684cb9a25606d63acfb773 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 18:03:07 +0200 Subject: [PATCH 18/48] don't crash when in XA PREPARE not all storage engines are 2pc-capable --- sql/handler.cc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index cf1fbfec465..3acca812a13 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -570,12 +570,20 @@ int ha_prepare(THD *thd) { int err; statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status); - if ((err= (*(*ht)->prepare)(thd, all))) + if ((*ht)->prepare) { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); - ha_rollback_trans(thd, all); - error=1; - break; + if ((err= (*(*ht)->prepare)(thd, all))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + ha_rollback_trans(thd, all); + error=1; + break; + } + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), (*ht)->name); } } } From 1ac26b4a6cfd5cf72b39e4fda31d2bb114463ad8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 10:30:06 -0700 Subject: [PATCH 19/48] Small tweak for random read performance (we shouldn't always tell the OS that we will be doing a linear scan). sql/examples/ha_tina.cc: Small tweak for random read performance. --- sql/examples/ha_tina.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index bbcdfb0dafb..8a9aa91c680 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -609,7 +609,8 @@ int ha_tina::rnd_init(bool scan) records= 0; chain_ptr= chain; #ifdef HAVE_MADVISE - (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); + if (scan) + (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); #endif DBUG_RETURN(0); From 792221e36579dbbec0f4335b49198a25d2a2ffd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 22:38:36 +0400 Subject: [PATCH 20/48] Fix bug #12922 if(sum(),...) with group from view returns wrong results Fields of view represented by Item_direct_view_ref. When complex expression such as if(sum()>...,...) is splited in simpler parts by refs was ignored. Beside this direct ref doesn't use it's result_field and thus can't store it's result in tmp table which is needed for sum() ... group. All this results in reported bug. Item::split_sum_func2() now converts Item_direct_view_ref to Item_ref to make fields from view being storable in tmp table. sql/item.h: Fix bug #12922 if(sum(),...) with group from view returns wrong results Added function ref_type() to distinguish Item_ref subclasses sql/item.cc: Fix bug #12922 if(sum(),...) with group from view returns wrong results Item::split_sum_func2() now converts Item_direct_view_ref to Item_ref to make fields from view being storable in tmp table. mysql-test/t/view.test: Test case for bug#12922 if(sum(),...) with group from view returns wrong results mysql-test/r/view.result: Test case for bug#12922 if(sum(),...) with group from view returns wrong results --- mysql-test/r/view.result | 9 +++++++++ mysql-test/t/view.test | 10 ++++++++++ sql/item.cc | 16 +++++++++------- sql/item.h | 4 ++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a544fb4b020..88c635509f5 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2151,3 +2151,12 @@ select * from v1; strcmp(f1,'a') drop view v1; drop table t1; +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +if(sum(f1)>1,f2,f3) +20 +0 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 97625632618..0e6fddf58ae 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2018,3 +2018,13 @@ create view v1 as select strcmp(f1,'a') from t1; select * from v1; drop view v1; drop table t1; + +# +# Bug #12922 if(sum(),...) with group from view returns wrong results +# +create table t1 (f1 int, f2 int,f3 int); +insert into t1 values (1,10,20),(2,0,0); +create view v1 as select * from t1; +select if(sum(f1)>1,f2,f3) from v1 group by f1; +drop view v1; +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index b4992faa65e..1edf0a470d3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1022,9 +1022,9 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, /* Will split complicated items and ignore simple ones */ split_sum_func(thd, ref_pointer_array, fields); } - else if ((type() == SUM_FUNC_ITEM || - (used_tables() & ~PARAM_TABLE_BIT)) && - type() != REF_ITEM) + else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) && + (type() != REF_ITEM || + ((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF)) { /* Replace item with a reference so that we can easily calculate @@ -1033,15 +1033,17 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, The test above is to ensure we don't do a reference for things that are constants (PARAM_TABLE_BIT is in effect a constant) or already referenced (for example an item in HAVING) + Exception is Item_direct_view_ref which we need to convert to + Item_ref to allow fields from view being stored in tmp table. */ uint el= fields.elements; - Item *new_item; - ref_pointer_array[el]= this; + Item *new_item, *real_item= real_item(); + + ref_pointer_array[el]= real_item; if (!(new_item= new Item_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set - fields.push_front(this); - ref_pointer_array[el]= this; + fields.push_front(real_item); thd->change_item_tree(ref, new_item); } } diff --git a/sql/item.h b/sql/item.h index b934e1f9f3f..f128c72413d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1537,6 +1537,7 @@ class Item_ref :public Item_ident protected: void set_properties(); public: + enum Ref_Type { REF, DIRECT_REF, VIEW_REF }; Field *result_field; /* Save result here */ Item **ref; Item_ref(Name_resolution_context *context_arg, @@ -1617,6 +1618,7 @@ public: void cleanup(); Item_field *filed_for_view_update() { return (*ref)->filed_for_view_update(); } + virtual Ref_Type ref_type() { return REF; } }; @@ -1641,6 +1643,7 @@ public: bool val_bool(); bool is_null(); bool get_date(TIME *ltime,uint fuzzydate); + virtual Ref_Type ref_type() { return DIRECT_REF; } }; /* @@ -1660,6 +1663,7 @@ public: bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; + virtual Ref_Type ref_type() { return VIEW_REF; } }; From eb061b654fb2a2aaef09e2bf8e7b3a8f300447be Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 23:03:56 +0400 Subject: [PATCH 21/48] Fix for Bug#12995: Inside function "Table 't4' was not locked with LOCK TABLES" Any form of HANDLER statement is forbidden from usage in stored procedures/functions. mysql-test/r/sp-error.result: Results for the test case for Bug#12995 added. mysql-test/t/sp-error.test: Test case for Bug#12995 added. sql/sql_yacc.yy: Forbid any form of "HANDLER" statement from use in stored procedures/functions. --- mysql-test/r/sp-error.result | 21 +++++++++++++++++++++ mysql-test/t/sp-error.test | 30 ++++++++++++++++++++++++++++++ sql/sql_yacc.yy | 15 +++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 1a061529fb0..09d829e9d12 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -765,3 +765,24 @@ OPTIMIZE TABLE t1; RETURN 1; END| ERROR 0A000: OPTIMIZE TABLE is not allowed in stored procedures +DROP FUNCTION IF EXISTS bug12995| +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 OPEN; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 READ FIRST; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +CREATE FUNCTION bug12995() RETURNS INT +BEGIN +HANDLER t1 CLOSE; +RETURN 1; +END| +ERROR 0A000: HANDLER is not allowed in stored procedures +SELECT bug12995()| +ERROR 42000: FUNCTION test.bug12995 does not exist diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index abb927ab3b8..9f91c32c104 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1099,6 +1099,36 @@ BEGIN OPTIMIZE TABLE t1; RETURN 1; END| +delimiter ;| + +# +# Bug##12995 "Inside function "Table 't4' was not locked with LOCK TABLES" +# +delimiter |; +--disable_warnings +DROP FUNCTION IF EXISTS bug12995| +--enable_warnings +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 OPEN; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 READ FIRST; + RETURN 1; +END| +--error ER_SP_BADSTATEMENT +CREATE FUNCTION bug12995() RETURNS INT +BEGIN + HANDLER t1 CLOSE; + RETURN 1; +END| +--error 1305 +SELECT bug12995()| +delimiter ;| # # BUG#NNNN: New bug synopsis diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cc286e4ff45..71adab4853c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8157,6 +8157,11 @@ handler: HANDLER_SYM table_ident OPEN_SYM opt_table_alias { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_OPEN; if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0)) YYABORT; @@ -8164,6 +8169,11 @@ handler: | HANDLER_SYM table_ident_nodb CLOSE_SYM { LEX *lex= Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_CLOSE; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; @@ -8171,6 +8181,11 @@ handler: | HANDLER_SYM table_ident_nodb READ_SYM { LEX *lex=Lex; + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER"); + YYABORT; + } lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ lex->current_select->select_limit= new Item_int((int32) 1); From d319c8ffbd95d885e3f64a3ab29c397b57be272d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 23:32:39 +0400 Subject: [PATCH 22/48] item.cc: Fix for fix bug#12922. sql/item.cc: Fix for fix bug#12922. --- sql/item.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 1edf0a470d3..56b03055968 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1037,13 +1037,13 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, Item_ref to allow fields from view being stored in tmp table. */ uint el= fields.elements; - Item *new_item, *real_item= real_item(); + Item *new_item, *real_itm= real_item(); - ref_pointer_array[el]= real_item; + ref_pointer_array[el]= real_itm; if (!(new_item= new Item_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set - fields.push_front(real_item); + fields.push_front(real_itm); thd->change_item_tree(ref, new_item); } } From f56d8901ece30131dd78bbc6c9f956a6035d954b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 18:07:51 -0700 Subject: [PATCH 23/48] Manual merge --- sql/item_sum.h | 515 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 364 insertions(+), 151 deletions(-) diff --git a/sql/item_sum.h b/sql/item_sum.h index d53d8d861ae..a1a232c4308 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -27,9 +27,9 @@ class Item_sum :public Item_result_field { public: enum Sumfunctype - { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, - MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, - UDF_SUM_FUNC, GROUP_CONCAT_FUNC + { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, + AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, + VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; Item **args, *tmp_args[2]; @@ -66,6 +66,9 @@ public: a temporary table. Similar to reset(), but must also store value in result_field. Like reset() it is supposed to reset start value to default. + This set of methods (reult_field(), reset_field, update_field()) of + Item_sum is used only if quick_group is not null. Otherwise + copy_or_same() is used to obtain a copy of this item. */ virtual void reset_field()=0; /* @@ -76,9 +79,24 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - virtual const char *func_name() const { return "?"; } + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print(), where it is applicable. + To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + + NOTE: for Items inherited from Item_sum, func_name() return part of + function name till first argument (including '(') to make difference in + names for functions with 'distinct' clause and without 'distinct' and + also to make printing of items inherited from Item_sum uniform. + */ + virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) - { return new Item_field(field);} + { return new Item_field(field); } table_map used_tables() const { return ~(table_map) 0; } /* Not used */ bool const_item() const { return 0; } bool is_null() { return null_value; } @@ -90,7 +108,8 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); - + virtual Field *create_tmp_field(bool group, TABLE *table, + uint convert_blob_length); bool walk (Item_processor processor, byte *argument); }; @@ -103,10 +122,14 @@ public: Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) val(); } /* Real as default */ + { + DBUG_ASSERT(fixed == 1); + return (longlong) val_real(); /* Real as default */ + } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void reset_field(); }; @@ -117,8 +140,9 @@ public: Item_sum_int(Item *item_par) :Item_sum_num(item_par) {} Item_sum_int(List &list) :Item_sum_num(list) {} Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} - double val() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } + double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; maybe_null=null_value=0; } @@ -127,25 +151,115 @@ public: class Item_sum_sum :public Item_sum_num { +protected: + Item_result hybrid_type; double sum; - void fix_length_and_dec() { maybe_null=null_value=1; } + my_decimal dec_buffs[2]; + uint curr_dec_buff; + void fix_length_and_dec(); - public: - Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {} - Item_sum_sum(THD *thd, Item_sum_sum *item) - :Item_sum_num(thd, item), sum(item->sum) {} +public: + Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {} + Item_sum_sum(THD *thd, Item_sum_sum *item); enum Sumfunctype sum_func () const {return SUM_FUNC;} void clear(); bool add(); - double val(); + double val_real(); + longlong val_int(); + String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return hybrid_type; } void reset_field(); void update_field(); void no_rows_in_result() {} - const char *func_name() const { return "sum"; } + const char *func_name() const { return "sum("; } Item *copy_or_same(THD* thd); }; + +/* Common class for SUM(DISTINCT), AVG(DISTINCT) */ + +class Unique; + +class Item_sum_distinct :public Item_sum_num +{ +protected: + /* storage for the summation result */ + ulonglong count; + Hybrid_type val; + /* storage for unique elements */ + Unique *tree; + TABLE *table; + enum enum_field_types table_field_type; + uint tree_key_length; +protected: + Item_sum_distinct(THD *thd, Item_sum_distinct *item); +public: + Item_sum_distinct(Item *item_par); + ~Item_sum_distinct(); + + bool setup(THD *thd); + void clear(); + void cleanup(); + bool add(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + longlong val_int(); + String *val_str(String *str); + + /* XXX: does it need make_unique? */ + + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } + void reset_field() {} // not used + void update_field() {} // not used + virtual void no_rows_in_result() {} + void fix_length_and_dec(); + enum Item_result result_type () const { return val.traits->type(); } + virtual void calculate_val_and_count(); + virtual bool unique_walk_function(void *elem); +}; + + +/* + Item_sum_sum_distinct - implementation of SUM(DISTINCT expr). + See also: MySQL manual, chapter 'Adding New Functions To MySQL' + and comments in item_sum.cc. +*/ + +class Item_sum_sum_distinct :public Item_sum_distinct +{ +private: + Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item) + :Item_sum_distinct(thd, item) {} +public: + Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {} + + enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } + const char *func_name() const { return "sum(distinct "; } + Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); } +}; + + +/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */ + +class Item_sum_avg_distinct: public Item_sum_distinct +{ +private: + Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original) + :Item_sum_distinct(thd, original) {} +public: + uint prec_increment; + Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {} + + void fix_length_and_dec(); + virtual void calculate_val_and_count(); + enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; } + const char *func_name() const { return "avg(distinct "; } + Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); } +}; + + class Item_sum_count :public Item_sum_int { longlong count; @@ -170,7 +284,7 @@ class Item_sum_count :public Item_sum_int void reset_field(); void cleanup(); void update_field(); - const char *func_name() const { return "count"; } + const char *func_name() const { return "count("; } Item *copy_or_same(THD* thd); }; @@ -180,80 +294,55 @@ class TMP_TABLE_PARAM; class Item_sum_count_distinct :public Item_sum_int { TABLE *table; - table_map used_table_cache; uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; - TREE tree_base; - TREE *tree; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_sum_count_distinct *original; - - uint key_length; - CHARSET_INFO *key_charset; - - /* - Calculated based on max_heap_table_size. If reached, - walk the tree and dump it into MyISAM table - */ - uint max_elements_in_tree; - - /* - The first few bytes of record ( at least one) - are just markers for deleted and NULLs. We want to skip them since - they will just bloat the tree without providing any valuable info - */ - int rec_offset; - /* If there are no blobs, we can use a tree, which is faster than heap table. In that case, we still use the table to help get things set up, but we insert nothing in it */ - bool use_tree; + Unique *tree; + /* + Following is 0 normal object and pointer to original one for copy + (to correctly free resources) + */ + Item_sum_count_distinct *original; + uint tree_key_length; + + bool always_null; // Set to 1 if the result is always NULL - int tree_to_myisam(); friend int composite_key_cmp(void* arg, byte* key1, byte* key2); friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2); - friend int simple_raw_key_cmp(void* arg, byte* key1, byte* key2); - friend int dump_leaf(byte* key, uint32 count __attribute__((unused)), - Item_sum_count_distinct* item); - public: +public: Item_sum_count_distinct(List &list) - :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0), - tmp_table_param(0), tree(&tree_base), original(0), use_tree(0), - always_null(0) + :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), + tree(0), original(0), always_null(FALSE) { quick_group= 0; } Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) :Item_sum_int(thd, item), table(item->table), - used_table_cache(item->used_table_cache), field_lengths(item->field_lengths), tmp_table_param(item->tmp_table_param), - tree(item->tree), original(item), key_length(item->key_length), - max_elements_in_tree(item->max_elements_in_tree), - rec_offset(item->rec_offset), use_tree(item->use_tree), + tree(item->tree), original(item), tree_key_length(item->tree_key_length), always_null(item->always_null) {} + ~Item_sum_count_distinct(); + void cleanup(); - table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } void clear(); bool add(); longlong val_int(); void reset_field() { return ;} // Never called void update_field() { return ; } // Never called - const char *func_name() const { return "count_distinct"; } + const char *func_name() const { return "count(distinct "; } bool setup(THD *thd); void make_unique(); Item *copy_or_same(THD* thd); void no_rows_in_result() {} - void print(String *str); }; @@ -265,43 +354,55 @@ class Item_avg_field :public Item_result_field { public: Field *field; - Item_avg_field(Item_sum_avg *item); + Item_result hybrid_type; + uint f_precision, f_scale, dec_bin_size; + uint prec_increment; + Item_avg_field(Item_result res_type, Item_sum_avg *item); enum Type type() const { return FIELD_AVG_ITEM; } - double val(); - longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; -class Item_sum_avg :public Item_sum_num +class Item_sum_avg :public Item_sum_sum { - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } - - double sum; +public: ulonglong count; + uint prec_increment; + uint f_precision, f_scale, dec_bin_size; - public: - Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {} + Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} Item_sum_avg(THD *thd, Item_sum_avg *item) - :Item_sum_num(thd, item), sum(item->sum), count(item->count) {} + :Item_sum_sum(thd, item), count(item->count), + prec_increment(item->prec_increment) {} + + void fix_length_and_dec(); enum Sumfunctype sum_func () const {return AVG_FUNC;} void clear(); bool add(); - double val(); + double val_real(); + // In SPs we might force the "wrong" type with select into a declare variable + longlong val_int() { return (longlong)val_real(); } + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); void reset_field(); void update_field(); Item *result_item(Field *field) - { return new Item_avg_field(this); } + { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} - const char *func_name() const { return "avg"; } + const char *func_name() const { return "avg("; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; class Item_sum_variance; @@ -310,14 +411,27 @@ class Item_variance_field :public Item_result_field { public: Field *field; + Item_result hybrid_type; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; + uint sample; + uint prec_increment; Item_variance_field(Item_sum_variance *item); enum Type type() const {return FIELD_VARIANCE_ITEM; } - double val(); - longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val(); } + double val_real(); + longlong val_int() + { /* can't be fix_fields()ed */ return (longlong) val_real(); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; @@ -335,30 +449,39 @@ public: class Item_sum_variance : public Item_sum_num { - double sum, sum_sqr; - ulonglong count; - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } + void fix_length_and_dec(); - public: - Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} - Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr), - count(item->count) {} +public: + Item_result hybrid_type; + double sum, sum_sqr; + my_decimal dec_sum[2], dec_sqr[2]; + int cur_dec; + ulonglong count; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; + uint sample; + uint prec_increment; + + Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par), + hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg) + {} + Item_sum_variance(THD *thd, Item_sum_variance *item); enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void clear(); bool add(); - double val(); + double val_real(); + my_decimal *val_decimal(my_decimal *); void reset_field(); void update_field(); Item *result_item(Field *field) { return new Item_variance_field(this); } void no_rows_in_result() {} - const char *func_name() const { return "variance"; } + const char *func_name() const + { return sample ? "var_samp(" : "variance("; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); + enum Item_result result_type () const { return hybrid_type; } }; class Item_sum_std; @@ -368,7 +491,10 @@ class Item_std_field :public Item_variance_field public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } - double val(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; /* @@ -378,26 +504,30 @@ public: class Item_sum_std :public Item_sum_variance { public: - Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {} + Item_sum_std(Item *item_par, uint sample_arg) + :Item_sum_variance(item_par, sample_arg) {} Item_sum_std(THD *thd, Item_sum_std *item) :Item_sum_variance(thd, item) {} enum Sumfunctype sum_func () const { return STD_FUNC; } - double val(); + double val_real(); Item *result_item(Field *field) { return new Item_std_field(this); } - const char *func_name() const { return "std"; } + const char *func_name() const { return "std("; } Item *copy_or_same(THD* thd); + enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; // This class is a string or number function depending on num_func class Item_sum_hybrid :public Item_sum { - protected: +protected: String value,tmp_value; double sum; longlong sum_int; + my_decimal sum_dec; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -408,22 +538,18 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), - cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item): - Item_sum(thd, item), value(item->value), - sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), - used_table_cache(item->used_table_cache), + cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(item->collation); } - bool fix_fields(THD *, TABLE_LIST *, Item **); + { collation.set(&my_charset_bin); } + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); + bool fix_fields(THD *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } void clear(); - double val(); + double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); void make_const() { used_table_cache=0; } @@ -434,9 +560,12 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(); void min_max_update_real_field(); void min_max_update_int_field(); + void min_max_update_decimal_field(); void cleanup(); bool any_value() { return was_values; } void no_rows_in_result(); + Field *create_tmp_field(bool group, TABLE *table, + uint convert_blob_length); }; @@ -448,7 +577,7 @@ public: enum Sumfunctype sum_func () const {return MIN_FUNC;} bool add(); - const char *func_name() const { return "min"; } + const char *func_name() const { return "min("; } Item *copy_or_same(THD* thd); }; @@ -461,7 +590,7 @@ public: enum Sumfunctype sum_func () const {return MAX_FUNC;} bool add(); - const char *func_name() const { return "max"; } + const char *func_name() const { return "max("; } Item *copy_or_same(THD* thd); }; @@ -482,7 +611,7 @@ public: void reset_field(); void update_field(); void fix_length_and_dec() - { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } + { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } }; @@ -492,7 +621,7 @@ public: Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_or"; } + const char *func_name() const { return "bit_or("; } Item *copy_or_same(THD* thd); }; @@ -503,7 +632,7 @@ class Item_sum_and :public Item_sum_bit Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {} Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_and"; } + const char *func_name() const { return "bit_and("; } Item *copy_or_same(THD* thd); }; @@ -513,7 +642,7 @@ class Item_sum_xor :public Item_sum_bit Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_xor"; } + const char *func_name() const { return "bit_xor("; } Item *copy_or_same(THD* thd); }; @@ -530,18 +659,21 @@ protected: udf_handler udf; public: - Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;} - Item_udf_sum( udf_func *udf_arg, List &list ) - :Item_sum( list ), udf(udf_arg) + Item_udf_sum(udf_func *udf_arg) + :Item_sum(), udf(udf_arg) + { quick_group=0; } + Item_udf_sum(udf_func *udf_arg, List &list) + :Item_sum(list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } + :Item_sum(thd, item), udf(item->udf) + { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; - return udf.fix_fields(thd,tables,this,this->arg_count,this->args); + return udf.fix_fields(thd, this, this->arg_count, this->args); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } @@ -551,21 +683,27 @@ public: void reset_field() {}; void update_field() {}; void cleanup(); + void print(String *str); }; class Item_sum_udf_float :public Item_udf_sum { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) Item_sum_udf_float::val(); } - double val(); + { + DBUG_ASSERT(fixed == 1); + return (longlong) Item_sum_udf_float::val_real(); + } + double val_real(); String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec() { fix_num_length_and_dec(); } Item *copy_or_same(THD* thd); }; @@ -574,15 +712,17 @@ class Item_sum_udf_float :public Item_udf_sum class Item_sum_udf_int :public Item_udf_sum { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int(); - double val() + double val_real() { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } Item *copy_or_same(THD* thd); @@ -592,43 +732,72 @@ public: class Item_sum_udf_str :public Item_udf_sum { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List &list) :Item_udf_sum(udf_arg,list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_udf_sum(thd, item) {} String *val_str(String *); - double val() + double val_real() { - int err; + int err_not_used; char *end_not_used; String *res; res=val_str(&str_value); return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(), - &end_not_used, &err) : 0.0; + &end_not_used, &err_not_used) : 0.0; } longlong val_int() { - int err; - String *res; res=val_str(&str_value); - return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0; + int err_not_used; + char *end; + String *res; + CHARSET_INFO *cs; + + if (!(res= val_str(&str_value))) + return 0; /* Null value */ + cs= res->charset(); + end= (char*) res->ptr()+res->length(); + return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used); } + my_decimal *val_decimal(my_decimal *dec); enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); Item *copy_or_same(THD* thd); }; + +class Item_sum_udf_decimal :public Item_udf_sum +{ +public: + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) + :Item_udf_sum(udf_arg, list) {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) + :Item_udf_sum(thd, item) {} + String *val_str(String *); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec() { fix_num_length_and_dec(); } + Item *copy_or_same(THD* thd); +}; + #else /* Dummy functions to get sql_yacc.cc compiled */ class Item_sum_udf_float :public Item_sum_num { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List &list) :Item_sum_num() {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - double val() { DBUG_ASSERT(fixed == 1); return 0.0; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void clear() {} bool add() { return 0; } void update_field() {} @@ -638,29 +807,50 @@ class Item_sum_udf_float :public Item_sum_num class Item_sum_udf_int :public Item_sum_num { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List &list) :Item_sum_num() {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } - double val() { DBUG_ASSERT(fixed == 1); return 0; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0; } void clear() {} bool add() { return 0; } void update_field() {} }; +class Item_sum_udf_decimal :public Item_sum_num +{ + public: + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List &list) + :Item_sum_num() {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) + :Item_sum_num(thd, item) {} + enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } + void clear() {} + bool add() { return 0; } + void update_field() {} +}; + + class Item_sum_udf_str :public Item_sum_num { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_str(udf_func *udf_arg, List &list) :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg, List &list) + :Item_sum_num() {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_num(thd, item) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - double val() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } + double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { maybe_null=1; max_length=0; } @@ -676,15 +866,26 @@ class MYSQL_ERROR; class Item_func_group_concat : public Item_sum { - THD *item_thd; TMP_TABLE_PARAM *tmp_table_param; - uint max_elements_in_tree; MYSQL_ERROR *warning; - uint key_length; - bool tree_mode; + String result; + String *separator; + TREE tree_base; + TREE *tree; + TABLE *table; + ORDER **order; + Name_resolution_context *context; + uint arg_count_order; // total count of ORDER BY items + uint arg_count_field; // count of arguments + uint count_cut_values; bool distinct; bool warning_for_row; bool always_null; + /* + Following is 0 normal object and pointer to original one for copy + (to correctly free resources) + */ + Item_func_group_concat *original; friend int group_concat_key_cmp_with_distinct(void* arg, byte* key1, byte* key2); @@ -693,7 +894,8 @@ class Item_func_group_concat : public Item_sum friend int group_concat_key_cmp_with_distinct_and_order(void* arg, byte* key1, byte* key2); - friend int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), + friend int dump_leaf_key(byte* key, + element_count count __attribute__((unused)), Item_func_group_concat *group_concat_item); public: @@ -719,8 +921,13 @@ class Item_func_group_concat : public Item_sum Item_func_group_concat(bool is_distinct,List *is_select, SQL_LIST *is_order,String *is_separator); +public: + Item_func_group_concat(Name_resolution_context *context_arg, + bool is_distinct, List *is_select, + SQL_LIST *is_order, String *is_separator); + Item_func_group_concat(THD *thd, Item_func_group_concat *item); - ~Item_func_group_concat(); + ~Item_func_group_concat() {} void cleanup(); enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} @@ -728,12 +935,12 @@ class Item_func_group_concat : public Item_sum virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); - void reset_field(); - bool fix_fields(THD *, TABLE_LIST *, Item **); + void reset_field() {} // not used + void update_field() {} // not used + bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); - virtual void update_field() {} - double val() + double val_real() { String *res; res=val_str(&str_value); return res ? my_atof(res->c_ptr()) : 0.0; @@ -748,8 +955,14 @@ class Item_func_group_concat : public Item_sum end_ptr= (char*) res->ptr()+ res->length(); return my_strtoll10(res->ptr(), &end_ptr, &error); } + my_decimal *val_decimal(my_decimal *decimal_value) + { + return val_decimal_from_string(decimal_value); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; From c2c2adfdfd7471d18c6258d258ac71b8667d3411 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Sep 2005 21:38:27 -0700 Subject: [PATCH 24/48] item_sum.cc, item_sum.h: Post-merge fix. sql/item_sum.h: Post-merge fix. sql/item_sum.cc: Post-merge fix. --- sql/item_sum.cc | 6 ------ sql/item_sum.h | 28 +++------------------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2ed1a18c3b0..13587d8a4c3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2972,12 +2972,6 @@ bool Item_func_group_concat::add() } -void Item_func_group_concat::reset_field() -{ - DBUG_ASSERT(0); -} - - bool Item_func_group_concat::fix_fields(THD *thd, Item **ref) { diff --git a/sql/item_sum.h b/sql/item_sum.h index a1a232c4308..87cc248e5e4 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -881,6 +881,7 @@ class Item_func_group_concat : public Item_sum bool distinct; bool warning_for_row; bool always_null; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) @@ -898,29 +899,6 @@ class Item_func_group_concat : public Item_sum element_count count __attribute__((unused)), Item_func_group_concat *group_concat_item); - public: - String result; - String *separator; - TREE tree_base; - TREE *tree; - TABLE *table; - ORDER **order; - TABLE_LIST *tables_list; - ulong group_concat_max_len; - uint arg_count_order; - uint arg_count_field; - uint field_list_offset; - uint count_cut_values; - bool no_appended; - /* - Following is 0 normal object and pointer to original one for copy - (to correctly free resources) - */ - Item_func_group_concat *original; - - Item_func_group_concat(bool is_distinct,List *is_select, - SQL_LIST *is_order,String *is_separator); - public: Item_func_group_concat(Name_resolution_context *context_arg, bool is_distinct, List *is_select, @@ -935,8 +913,8 @@ public: virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); - void reset_field() {} // not used - void update_field() {} // not used + void reset_field() { DBUG_ASSERT(0); } // not used + void update_field() { DBUG_ASSERT(0); } // not used bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); From 34422f78c17ced6ae43a030a4d772273b7406405 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 12:09:30 +0400 Subject: [PATCH 25/48] Modified test case for bug #12517 --- mysql-test/r/connect.result | 14 ++------------ mysql-test/t/connect.test | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index 293ad37c31a..68c86b80e60 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -1,3 +1,4 @@ +drop table if exists t1,t2; show tables; Tables_in_mysql columns_priv @@ -65,19 +66,8 @@ show tables; Tables_in_test delete from mysql.user where user=_binary"test"; flush privileges; -use test; -drop table if exists t1; -Warnings: -Note 1051 Unknown table 't1' create table t1 (id integer not null auto_increment primary key); -drop table if exists t2; -Warnings: -Note 1051 Unknown table 't2' create temporary table t2(id integer not null auto_increment primary key); set @id := 1; delete from t1 where id like @id; -use test; -drop table if exists t2; -Warnings: -Note 1051 Unknown table 't2' -drop table if exists t1; +drop table t1; diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 9acc18a0cee..ff15d74e5ac 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -6,6 +6,10 @@ # This test makes no sense with the embedded server --source include/not_embedded.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + #connect (con1,localhost,root,,""); #show tables; connect (con1,localhost,root,,mysql); @@ -77,22 +81,18 @@ show tables; delete from mysql.user where user=_binary"test"; flush privileges; -# Test for bug #12517. +# +# Bug#12517: Clear user variables and replication events before +# closing temp tables in thread cleanup. connect (con2,localhost,root,,test); connection con2; -use test; -drop table if exists t1; create table t1 (id integer not null auto_increment primary key); -drop table if exists t2; create temporary table t2(id integer not null auto_increment primary key); set @id := 1; delete from t1 where id like @id; disconnect con2; -sleep 5; -connect (con1,localhost,root,,test); -connection con1; -use test; -drop table if exists t2; -drop table if exists t1; +--sleep 5 +connection default; +drop table t1; # End of 4.1 tests From 9adffe29269cd56b83ae87d27ed37ff0029fcf9f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 11:29:52 +0300 Subject: [PATCH 26/48] Fix for BUG#12977. mysql-test/r/select.result: Test for BUG#12977. mysql-test/t/select.test: Test for BUG#12977. sql/sql_base.cc: - Compare table qualifier of qualified fields only with tables that are not natural joins or their operands. - For qualified fields perform recursive search in all operands of natural joins that are nested joins. - Symmetrically detect ambiguous columns for both operands of NATURAL/USING joins. --- mysql-test/r/select.result | 15 +++++++++++++++ mysql-test/t/select.test | 22 ++++++++++++++++++++++ sql/sql_base.cc | 28 +++++++++++++++++++++------- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 0d5c1aed485..24c89039566 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2897,3 +2897,18 @@ select * from t1 natural join t2 where a = 'b'; a b drop table t1, t2; +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); +ERROR 23000: Column 'id' in from clause is ambiguous +drop table t1, t2, t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index fad01ac9acf..62687a869b7 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2465,3 +2465,25 @@ insert into t2 values ('b'),('c'),('d'); select a from t1 natural join t2; select * from t1 natural join t2 where a = 'b'; drop table t1, t2; + +# +# Bug #12977 Compare table names with qualifying field tables only +# for base tables, search all nested join operands of natural joins. +# + +CREATE TABLE t1 (`id` TINYINT); +CREATE TABLE t2 (`id` TINYINT); +CREATE TABLE t3 (`id` TINYINT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (2); +INSERT INTO t3 VALUES (3); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT t1.id,t3.id FROM t1 JOIN t2 ON (t2.notacolumn=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM t1 JOIN t2 ON (t2.id=t1.id) LEFT JOIN t3 USING (id); +-- error 1052 +SELECT id,t3.id FROM (t1 JOIN t2 ON (t2.id=t1.id)) LEFT JOIN t3 USING (id); + +drop table t1, t2, t3; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7025568a1c8..07c5896dd2e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2877,14 +2877,15 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, /* Check that the table and database that qualify the current field name are the same as the table we are going to search for the field. - This is done differently for NATURAL/USING joins because there we can't - simply compare the qualifying table and database names with the ones of + This is done differently for NATURAL/USING joins or nested joins that + are operands of NATURAL/USING joins because there we can't simply + compare the qualifying table and database names with the ones of 'table_list' because each field in such a join may originate from a different table. TODO: Ensure that table_name, db_name and tables->db always points to something ! */ - if (!table_list->is_natural_join && + if (!(table_list->nested_join && table_list->join_columns) && table_name && table_name[0] && (my_strcasecmp(table_alias_charset, table_list->alias, table_name) || (db_name && db_name[0] && table_list->db && table_list->db[0] && @@ -2899,8 +2900,13 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, register_tree_change))) *actual_table= table_list; } - else if (table_list->is_natural_join) + else if (table_list->nested_join && table_list->join_columns) { + /* + If this is a NATURAL/USING join, or an operand of such join which is a + join itself, and the field name is qualified, then search for the field + in the operands of the join. + */ if (table_name && table_name[0]) { /* @@ -2922,7 +2928,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, } /* Non-qualified field, search directly in the result columns of the - natural join. + natural join. The condition of the outer IF is true for the top-most + natural join, thus if the field is not qualified, we will search + directly the top-most NATURAL/USING join. */ fld= find_field_in_natural_join(thd, table_list, name, length, ref, /* TIMOUR_TODO: check this with Sanja */ @@ -3528,10 +3536,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (add_columns && is_created_2) table_ref_2->join_columns->push_back(cur_nj_col_2); - /* Compare the two columns and check for duplicate common fields. */ + /* + Compare the two columns and check for duplicate common fields. + A common field is duplicate either if it was already found in + table_ref_2 (then found == TRUE), or if a field in table_ref_2 + was already matched by some previous field in table_ref_1 + (then cur_nj_col_2->is_common == TRUE). + */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { - if (found) + if (found || cur_nj_col_2->is_common) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; From e53871c38a0bb6f874cfdfe4e44db9a93c095642 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 11:34:55 +0200 Subject: [PATCH 27/48] Bug #13054 start backup command return may be interrpted --- ndb/include/kernel/signaldata/BackupImpl.hpp | 9 +- .../kernel/signaldata/BackupSignalData.hpp | 5 +- .../kernel/signaldata/NFCompleteRep.hpp | 18 +- ndb/include/kernel/signaldata/NodeFailRep.hpp | 28 +- ndb/src/kernel/blocks/backup/Backup.cpp | 42 ++- ndb/src/kernel/blocks/backup/Backup.hpp | 1 + ndb/src/mgmsrv/MgmtSrvr.cpp | 265 ++++++++--------- ndb/src/mgmsrv/MgmtSrvr.hpp | 3 - ndb/src/ndbapi/Makefile.am | 3 +- ndb/src/ndbapi/SignalSender.cpp | 270 ++++++++++++++++++ ndb/src/ndbapi/SignalSender.hpp | 83 ++++++ 11 files changed, 527 insertions(+), 200 deletions(-) create mode 100644 ndb/src/ndbapi/SignalSender.cpp create mode 100644 ndb/src/ndbapi/SignalSender.hpp diff --git a/ndb/include/kernel/signaldata/BackupImpl.hpp b/ndb/include/kernel/signaldata/BackupImpl.hpp index 2032e2347b5..298440ad377 100644 --- a/ndb/include/kernel/signaldata/BackupImpl.hpp +++ b/ndb/include/kernel/signaldata/BackupImpl.hpp @@ -33,7 +33,7 @@ class DefineBackupReq { friend bool printDEFINE_BACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 8 + NdbNodeBitmask::Size); + STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size); private: /** @@ -60,6 +60,13 @@ private: * Length of backup data */ Uint32 backupDataLen; + + /** + * Backup flags + */ + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class DefineBackupRef { diff --git a/ndb/include/kernel/signaldata/BackupSignalData.hpp b/ndb/include/kernel/signaldata/BackupSignalData.hpp index b38dd8d14b2..e1b8c6203a1 100644 --- a/ndb/include/kernel/signaldata/BackupSignalData.hpp +++ b/ndb/include/kernel/signaldata/BackupSignalData.hpp @@ -36,11 +36,14 @@ class BackupReq { friend bool printBACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 2 ); + STATIC_CONST( SignalLength = 3 ); private: Uint32 senderData; Uint32 backupDataLen; + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class BackupData { diff --git a/ndb/include/kernel/signaldata/NFCompleteRep.hpp b/ndb/include/kernel/signaldata/NFCompleteRep.hpp index c8bde705a86..764da85b163 100644 --- a/ndb/include/kernel/signaldata/NFCompleteRep.hpp +++ b/ndb/include/kernel/signaldata/NFCompleteRep.hpp @@ -30,28 +30,12 @@ * from the failed NDB node * */ -class NFCompleteRep { - /** - * Sender(s) - */ - friend class Dbdict; - friend class Dblqh; - friend class Dbtc; - friend class Qmgr; - - /** - * Sender/Reciver - */ - friend class Dbdih; - friend class ClusterMgr; +struct NFCompleteRep { friend bool printNF_COMPLETE_REP(FILE *, const Uint32 *, Uint32, Uint16); -public: STATIC_CONST( SignalLength = 5 ); -private: - /** * Which block has completed... * diff --git a/ndb/include/kernel/signaldata/NodeFailRep.hpp b/ndb/include/kernel/signaldata/NodeFailRep.hpp index 060acd6a3e2..fe57ba1a712 100644 --- a/ndb/include/kernel/signaldata/NodeFailRep.hpp +++ b/ndb/include/kernel/signaldata/NodeFailRep.hpp @@ -24,34 +24,8 @@ * This signals is sent by Qmgr to NdbCntr * and then from NdbCntr sent to: dih, dict, lqh, tc & API */ -class NodeFailRep { - /** - * Sender(s) - */ - friend class Qmgr; - - /** - * Sender(s) / Reciver(s) - */ - friend class Ndbcntr; - friend class Dbdict; - - /** - * Reciver(s) - */ - friend class Dbdih; - friend class Dblqh; - friend class Dbtc; - friend class ClusterMgr; - friend class Trix; - friend class Backup; - friend class Suma; - friend class Grep; - friend class SafeCounterManager; - -public: +struct NodeFailRep { STATIC_CONST( SignalLength = 3 + NodeBitmask::Size ); -private: Uint32 failNo; diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 3334d69ae89..04b5a00494c 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -69,6 +69,9 @@ static const Uint32 BACKUP_SEQUENCE = 0x1F000000; static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE; +#define SEND_BACKUP_STARTED_FLAG(A) (((A) & 0x3) > 0) +#define SEND_BACKUP_COMPLETED_FLAG(A) (((A) & 0x3) > 1) + void Backup::execSTTOR(Signal* signal) { @@ -852,7 +855,8 @@ Backup::execBACKUP_REQ(Signal* signal) const Uint32 senderData = req->senderData; const BlockReference senderRef = signal->senderBlockRef(); const Uint32 dataLen32 = req->backupDataLen; // In 32 bit words - + const Uint32 flags = signal->getLength() > 2 ? req->flags : 2; + if(getOwnNodeId() != getMasterNodeId()) { jam(); sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster); @@ -894,6 +898,7 @@ Backup::execBACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = senderRef; ptr.p->clientData = senderData; + ptr.p->flags = flags; ptr.p->masterRef = reference(); ptr.p->nodes = c_aliveNodes; ptr.p->backupId = 0; @@ -931,7 +936,10 @@ void Backup::sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode) { jam(); - sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode); + if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) + { + sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode); + } cleanup(signal, ptr); } @@ -1098,6 +1106,7 @@ Backup::sendDefineBackupReq(Signal *signal, BackupRecordPtr ptr) req->backupKey[1] = ptr.p->backupKey[1]; req->nodes = ptr.p->nodes; req->backupDataLen = ptr.p->backupDataLen; + req->flags = ptr.p->flags; ptr.p->masterData.gsn = GSN_DEFINE_BACKUP_REQ; ptr.p->masterData.sendCounter = ptr.p->nodes; @@ -1193,13 +1202,18 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) /** * Reply to client */ + CRASH_INSERTION((10034)); + BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); conf->backupId = ptr.p->backupId; conf->senderData = ptr.p->clientData; conf->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, - BackupConf::SignalLength, JBB); - + if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) + { + sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, + BackupConf::SignalLength, JBB); + } + signal->theData[0] = EventReport::BackupStarted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2090,9 +2104,12 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) rep->noOfLogBytes = ptr.p->noOfLogBytes; rep->noOfLogRecords = ptr.p->noOfLogRecords; rep->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, - BackupCompleteRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, + BackupCompleteRep::SignalLength, JBB); + } + signal->theData[0] = EventReport::BackupCompleted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2133,9 +2150,11 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr) rep->backupId = ptr.p->backupId; rep->senderData = ptr.p->clientData; rep->reason = ptr.p->errorCode; - sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, - BackupAbortRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, + BackupAbortRep::SignalLength, JBB); + } signal->theData[0] = EventReport::BackupAborted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2267,6 +2286,7 @@ Backup::execDEFINE_BACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = req->clientRef; ptr.p->clientData = req->clientData; + ptr.p->flags = req->flags; ptr.p->masterRef = senderRef; ptr.p->nodes = req->nodes; ptr.p->backupId = backupId; diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index 7bcea5655b4..7780d05ab9e 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -413,6 +413,7 @@ public: Uint32 clientRef; Uint32 clientData; + Uint32 flags; Uint32 backupId; Uint32 backupKey[2]; Uint32 masterRef; diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index acab2ef9eac..e9d3ce19076 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,8 @@ #include #include +#include + //#define MGM_SRV_DEBUG #ifdef MGM_SRV_DEBUG #define DEBUG(x) do ndbout << x << endl; while(0) @@ -709,6 +713,15 @@ int MgmtSrvr::okToSendTo(NodeId processId, bool unCond) } } +void report_unknown_signal(SimpleSignal *signal) +{ + g_eventLogger.error("Unknown signal received. SignalNumber: " + "%i from (%d, %x)", + signal->readSignalNumber(), + refToNode(signal->header.theSendersBlockRef), + refToBlock(signal->header.theSendersBlockRef)); +} + /***************************************************************************** * Starting and stopping database nodes ****************************************************************************/ @@ -1911,81 +1924,6 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal) } break; - case GSN_BACKUP_CONF:{ - const BackupConf * const conf = - CAST_CONSTPTR(BackupConf, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupStarted; - event.Started.BackupId = conf->backupId; - event.Nodes = conf->nodes; -#ifdef VM_TRACE - ndbout_c("Backup master is %d", refToNode(signal->theSendersBlockRef)); -#endif - backupCallback(event); - } - break; - - case GSN_BACKUP_REF:{ - const BackupRef * const ref = - CAST_CONSTPTR(BackupRef, signal->getDataPtr()); - Uint32 errCode = ref->errorCode; - if(ref->errorCode == BackupRef::IAmNotMaster){ - const Uint32 aNodeId = refToNode(ref->masterRef); -#ifdef VM_TRACE - ndbout_c("I'm not master resending to %d", aNodeId); -#endif - theWaitNode= aNodeId; - NdbApiSignal aSignal(_ownReference); - BackupReq* req = CAST_PTR(BackupReq, aSignal.getDataPtrSend()); - aSignal.set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); - req->senderData = 19; - req->backupDataLen = 0; - - int i = theFacade->sendSignalUnCond(&aSignal, aNodeId); - if(i == 0){ - return; - } - errCode = 5030; - } - BackupEvent event; - event.Event = BackupEvent::BackupFailedToStart; - event.FailedToStart.ErrorCode = errCode; - backupCallback(event); - break; - } - - case GSN_BACKUP_ABORT_REP:{ - const BackupAbortRep * const rep = - CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupAborted; - event.Aborted.Reason = rep->reason; - event.Aborted.BackupId = rep->backupId; - event.Aborted.ErrorCode = rep->reason; - backupCallback(event); - } - break; - - case GSN_BACKUP_COMPLETE_REP:{ - const BackupCompleteRep * const rep = - CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupCompleted; - event.Completed.BackupId = rep->backupId; - - event.Completed.NoOfBytes = rep->noOfBytes; - event.Completed.NoOfLogBytes = rep->noOfLogBytes; - event.Completed.NoOfRecords = rep->noOfRecords; - event.Completed.NoOfLogRecords = rep->noOfLogRecords; - event.Completed.stopGCP = rep->stopGCP; - event.Completed.startGCP = rep->startGCP; - event.Nodes = rep->nodes; - - backupCallback(event); - } - break; - case GSN_MGM_LOCK_CONFIG_REP: case GSN_MGM_LOCK_CONFIG_REQ: case GSN_MGM_UNLOCK_CONFIG_REP: @@ -2446,6 +2384,9 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData) int MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) { + SignalSender ss(theFacade); + ss.lock(); // lock will be released on exit + bool next; NodeId nodeId = 0; while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && @@ -2453,49 +2394,125 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) if(!next) return NO_CONTACT_WITH_DB_NODES; - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + SimpleSignal ssig; - BackupReq* req = CAST_PTR(BackupReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); + BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend()); + ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, + BackupReq::SignalLength); req->senderData = 19; req->backupDataLen = 0; + assert(waitCompleted < 3); + req->flags = waitCompleted & 0x3; - int result; - if (waitCompleted == 2) { - result = sendRecSignal(nodeId, WAIT_BACKUP_COMPLETED, - signal, true, 48*60*60*1000 /* 48 hours */); - } - else if (waitCompleted == 1) { - result = sendRecSignal(nodeId, WAIT_BACKUP_STARTED, - signal, true, 5*60*1000 /*5 mins*/); - } - else { - result = sendRecSignal(nodeId, NO_WAIT, signal, true); - } - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } + BackupEvent event; + int do_send = 1; + while (1) { + if (do_send) + { + SendStatus result = ss.sendSignal(nodeId, &ssig); + if (result != SEND_OK) { + return SEND_OR_RECEIVE_FAILED; + } + if (waitCompleted == 0) + return 0; + do_send = 0; + } + SimpleSignal *signal = ss.waitFor(); - if (waitCompleted){ - switch(m_lastBackupEvent.Event){ - case BackupEvent::BackupCompleted: - backupId = m_lastBackupEvent.Completed.BackupId; + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_BACKUP_CONF:{ + const BackupConf * const conf = + CAST_CONSTPTR(BackupConf, signal->getDataPtr()); + event.Event = BackupEvent::BackupStarted; + event.Started.BackupId = conf->backupId; + event.Nodes = conf->nodes; +#ifdef VM_TRACE + ndbout_c("Backup(%d) master is %d", conf->backupId, + refToNode(signal->header.theSendersBlockRef)); +#endif + backupId = conf->backupId; + if (waitCompleted == 1) + return 0; + // wait for next signal break; - case BackupEvent::BackupStarted: - backupId = m_lastBackupEvent.Started.BackupId; + } + case GSN_BACKUP_COMPLETE_REP:{ + const BackupCompleteRep * const rep = + CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Backup(%d) completed %d", rep->backupId); +#endif + event.Event = BackupEvent::BackupCompleted; + event.Completed.BackupId = rep->backupId; + + event.Completed.NoOfBytes = rep->noOfBytes; + event.Completed.NoOfLogBytes = rep->noOfLogBytes; + event.Completed.NoOfRecords = rep->noOfRecords; + event.Completed.NoOfLogRecords = rep->noOfLogRecords; + event.Completed.stopGCP = rep->stopGCP; + event.Completed.startGCP = rep->startGCP; + event.Nodes = rep->nodes; + + backupId = rep->backupId; + return 0; + } + case GSN_BACKUP_REF:{ + const BackupRef * const ref = + CAST_CONSTPTR(BackupRef, signal->getDataPtr()); + if(ref->errorCode == BackupRef::IAmNotMaster){ + nodeId = refToNode(ref->masterRef); +#ifdef VM_TRACE + ndbout_c("I'm not master resending to %d", nodeId); +#endif + do_send = 1; // try again + continue; + } + event.Event = BackupEvent::BackupFailedToStart; + event.FailedToStart.ErrorCode = ref->errorCode; + return ref->errorCode; + } + case GSN_BACKUP_ABORT_REP:{ + const BackupAbortRep * const rep = + CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); + event.Event = BackupEvent::BackupAborted; + event.Aborted.Reason = rep->reason; + event.Aborted.BackupId = rep->backupId; + event.Aborted.ErrorCode = rep->reason; +#ifdef VM_TRACE + ndbout_c("Backup %d aborted", rep->backupId); +#endif + return rep->reason; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Node %d fail completed", rep->failedNodeId); +#endif + if (rep->failedNodeId == nodeId || + waitCompleted == 1) + return 1326; + // wait for next signal + // master node will report aborted backup break; - case BackupEvent::BackupFailedToStart: - return m_lastBackupEvent.FailedToStart.ErrorCode; - case BackupEvent::BackupAborted: - return m_lastBackupEvent.Aborted.ErrorCode; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Node %d failed", rep->failNo); +#endif + if (rep->failNo == nodeId || + waitCompleted == 1) + // wait for next signal + // master node will report aborted backup + break; + } default: - return -1; - break; + report_unknown_signal(signal); + return SEND_OR_RECEIVE_FAILED; } } @@ -2535,36 +2552,6 @@ MgmtSrvr::abortBackup(Uint32 backupId) return 0; } -void -MgmtSrvr::backupCallback(BackupEvent & event) -{ - DBUG_ENTER("MgmtSrvr::backupCallback"); - m_lastBackupEvent = event; - switch(event.Event){ - case BackupEvent::BackupFailedToStart: - DBUG_PRINT("info",("BackupEvent::BackupFailedToStart")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupAborted: - DBUG_PRINT("info",("BackupEvent::BackupAborted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupCompleted: - DBUG_PRINT("info",("BackupEvent::BackupCompleted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupStarted: - if(theWaitState == WAIT_BACKUP_STARTED) - { - DBUG_PRINT("info",("BackupEvent::BackupStarted NO_WAIT")); - theWaitState = NO_WAIT; - } else { - DBUG_PRINT("info",("BackupEvent::BackupStarted")); - } - } - DBUG_VOID_RETURN; -} - /***************************************************************************** * Global Replication diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp index c132852338b..f8c244a1bf1 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -757,9 +757,6 @@ private: static void *signalRecvThread_C(void *); void signalRecvThreadRun(); - void backupCallback(BackupEvent &); - BackupEvent m_lastBackupEvent; - Config *_props; int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am index 9f8a851b995..1ba80ef7d85 100644 --- a/ndb/src/ndbapi/Makefile.am +++ b/ndb/src/ndbapi/Makefile.am @@ -35,7 +35,8 @@ libndbapi_la_SOURCES = \ NdbDictionaryImpl.cpp \ DictCache.cpp \ ndb_cluster_connection.cpp \ - NdbBlob.cpp + NdbBlob.cpp \ + SignalSender.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp new file mode 100644 index 00000000000..0a23529dc73 --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.cpp @@ -0,0 +1,270 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "SignalSender.hpp" +#include +#include +#include +#include + +SimpleSignal::SimpleSignal(bool dealloc){ + memset(this, 0, sizeof(* this)); + deallocSections = dealloc; +} + +SimpleSignal::~SimpleSignal(){ + if(!deallocSections) + return; + if(ptr[0].p != 0) delete []ptr[0].p; + if(ptr[1].p != 0) delete []ptr[1].p; + if(ptr[2].p != 0) delete []ptr[2].p; +} + +void +SimpleSignal::set(class SignalSender& ss, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len){ + + header.theTrace = trace; + header.theReceiversBlockNumber = recBlock; + header.theVerId_signalNumber = gsn; + header.theLength = len; + header.theSendersBlockRef = refToBlock(ss.getOwnRef()); +} + +void +SimpleSignal::print(FILE * out){ + fprintf(out, "---- Signal ----------------\n"); + SignalLoggerManager::printSignalHeader(out, header, 0, 0, false); + SignalLoggerManager::printSignalData(out, header, theData); + for(Uint32 i = 0; i= 7){ + fprintf(out, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + signalData[0], signalData[1], signalData[2], signalData[3], + signalData[4], signalData[5], signalData[6]); + len -= 7; + signalData += 7; + } + if(len > 0){ + fprintf(out, " H\'%.8x", signalData[0]); + for(Uint32 i = 1; iopen(this, execSignal, execNodeStatus); + assert(m_blockNo > 0); +} + +SignalSender::~SignalSender(){ + int i; + if (m_lock) + unlock(); + theFacade->close(m_blockNo,0); + // free these _after_ closing theFacade to ensure that + // we delete all signals + for (i= m_jobBuffer.size()-1; i>= 0; i--) + delete m_jobBuffer[i]; + for (i= m_usedBuffer.size()-1; i>= 0; i--) + delete m_usedBuffer[i]; + NdbCondition_Destroy(m_cond); +} + +int SignalSender::lock() +{ + if (NdbMutex_Lock(theFacade->theMutexPtr)) + return -1; + m_lock= 1; + return 0; +} + +int SignalSender::unlock() +{ + if (NdbMutex_Unlock(theFacade->theMutexPtr)) + return -1; + m_lock= 0; + return 0; +} + +Uint32 +SignalSender::getOwnRef() const { + return numberToRef(m_blockNo, theFacade->ownId()); +} + +Uint32 +SignalSender::getAliveNode() const{ + return theFacade->get_an_alive_node(); +} + +const ClusterMgr::Node & +SignalSender::getNodeInfo(Uint16 nodeId) const { + return theFacade->theClusterMgr->getNodeInfo(nodeId); +} + +Uint32 +SignalSender::getNoOfConnectedNodes() const { + return theFacade->theClusterMgr->getNoOfConnectedNodes(); +} + +SendStatus +SignalSender::sendSignal(Uint16 nodeId, const SimpleSignal * s){ + return theFacade->theTransporterRegistry->prepareSend(&s->header, + 1, // JBB + &s->theData[0], + nodeId, + &s->ptr[0]); +} + +template +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis, T & t) +{ + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + return s; + } + + NDB_TICKS now = NdbTick_CurrentMillisecond(); + NDB_TICKS stop = now + timeOutMillis; + Uint32 wait = (timeOutMillis == 0 ? 10 : timeOutMillis); + do { + NdbCondition_WaitTimeout(m_cond, + theFacade->theMutexPtr, + wait); + + + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + m_usedBuffer.push_back(s); + return s; + } + + now = NdbTick_CurrentMillisecond(); + wait = (timeOutMillis == 0 ? 10 : stop - now); + } while(stop > now || timeOutMillis == 0); + + return 0; +} + +class WaitForAny { +public: + SimpleSignal * check(Vector & m_jobBuffer){ + if(m_jobBuffer.size() > 0){ + SimpleSignal * s = m_jobBuffer[0]; + m_jobBuffer.erase(0); + return s; + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis){ + + WaitForAny w; + return waitFor(timeOutMillis, w); +} + +class WaitForNode { +public: + Uint32 m_nodeId; + SimpleSignal * check(Vector & m_jobBuffer){ + Uint32 len = m_jobBuffer.size(); + for(Uint32 i = 0; iheader.theSendersBlockRef) == m_nodeId){ + SimpleSignal * s = m_jobBuffer[i]; + m_jobBuffer.erase(i); + return s; + } + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint16 nodeId, Uint32 timeOutMillis){ + + WaitForNode w; + w.m_nodeId = nodeId; + return waitFor(timeOutMillis, w); +} + +#include + +void +SignalSender::execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]){ + SimpleSignal * s = new SimpleSignal(true); + s->header = * signal; + memcpy(&s->theData[0], signal->getDataPtr(), 4 * s->header.theLength); + for(Uint32 i = 0; iheader.m_noOfSections; i++){ + s->ptr[i].p = new Uint32[ptr[i].sz]; + s->ptr[i].sz = ptr[i].sz; + memcpy(s->ptr[i].p, ptr[i].p, 4 * ptr[i].sz); + } + SignalSender * ss = (SignalSender*)signalSender; + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +void +SignalSender::execNodeStatus(void* signalSender, + Uint32 nodeId, + bool alive, + bool nfCompleted){ + if (alive) { + // node connected + return; + } + + SimpleSignal * s = new SimpleSignal(true); + SignalSender * ss = (SignalSender*)signalSender; + + // node disconnected + if(nfCompleted) + { + // node shutdown complete + s->header.theVerId_signalNumber = GSN_NF_COMPLETEREP; + NFCompleteRep *rep = (NFCompleteRep *)s->getDataPtrSend(); + rep->failedNodeId = nodeId; + } + else + { + // node failure + s->header.theVerId_signalNumber = GSN_NODE_FAILREP; + NodeFailRep *rep = (NodeFailRep *)s->getDataPtrSend(); + rep->failNo = nodeId; + } + + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +template SimpleSignal* SignalSender::waitFor(unsigned, WaitForNode&); +template SimpleSignal* SignalSender::waitFor(unsigned, WaitForAny&); +template Vector; + diff --git a/ndb/src/ndbapi/SignalSender.hpp b/ndb/src/ndbapi/SignalSender.hpp new file mode 100644 index 00000000000..4b991460034 --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.hpp @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef SIGNAL_SENDER_HPP +#define SIGNAL_SENDER_HPP + +#include +#include "TransporterFacade.hpp" +#include + +struct SimpleSignal { +public: + SimpleSignal(bool dealloc = false); + ~SimpleSignal(); + + void set(class SignalSender&, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len); + + struct SignalHeader header; + Uint32 theData[25]; + LinearSectionPtr ptr[3]; + + int readSignalNumber() {return header.theVerId_signalNumber; } + Uint32 *getDataPtrSend() { return theData; } + const Uint32 *getDataPtr() const { return theData; } + + void print(FILE * out = stdout); +private: + bool deallocSections; +}; + +class SignalSender { +public: + SignalSender(TransporterFacade *facade); + virtual ~SignalSender(); + + int lock(); + int unlock(); + + Uint32 getOwnRef() const; + Uint32 getAliveNode() const; + const ClusterMgr::Node &getNodeInfo(Uint16 nodeId) const; + Uint32 getNoOfConnectedNodes() const; + + SendStatus sendSignal(Uint16 nodeId, const SimpleSignal *); + + SimpleSignal * waitFor(Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint16 gsn, Uint32 timeOutMillis = 0); +private: + int m_blockNo; + TransporterFacade * theFacade; + + static void execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]); + + static void execNodeStatus(void* signalSender, Uint32 nodeId, + bool alive, bool nfCompleted); + + int m_lock; + struct NdbCondition * m_cond; + Vector m_jobBuffer; + Vector m_usedBuffer; + + template + SimpleSignal * waitFor(Uint32 timeOutMillis, T & t); +}; + +#endif From bcd319283cba0396bc948129fb10686f529e6b53 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 11:36:12 +0200 Subject: [PATCH 28/48] yassl fix for ia64 + icc extra/yassl/taocrypt/include/runtime.hpp: Check for both __ICC and __INTEL_COMPILER extra/yassl/taocrypt/include/types.hpp: Check for both __ICC and __INTEL_COMPILER --- extra/yassl/taocrypt/include/runtime.hpp | 4 +++- extra/yassl/taocrypt/include/types.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp index f506040f0d8..254e67a7f64 100644 --- a/extra/yassl/taocrypt/include/runtime.hpp +++ b/extra/yassl/taocrypt/include/runtime.hpp @@ -25,7 +25,8 @@ -#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) && !defined(__ICC) +#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) +#if !(defined(__ICC) || defined(__INTEL_COMPILER)) #define yaSSL_NEW_HPP @@ -46,5 +47,6 @@ static int __cxa_pure_virtual() } // extern "C" #endif // __GNUC__ > 2 +#endif // ! _ICC #endif // yaSSL_NEW_HPP && __GNUC__ diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp index 92164eaaab4..db9c3792bbd 100644 --- a/extra/yassl/taocrypt/include/types.hpp +++ b/extra/yassl/taocrypt/include/types.hpp @@ -61,9 +61,10 @@ typedef unsigned int word32; // compilers we've found 64-bit multiply insructions for #if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX) +#if !(defined(__ICC) || defined(__INTEL_COMPILER)) #define HAVE_64_MULTIPLY #endif - +#endif #if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \ || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__)) From ef0a284a4c17a942acb96e430ccc360cf3710b6e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 15:24:21 +0200 Subject: [PATCH 29/48] corrected prev fix for bug #13054 so that _only_ backup master replies to API --- ndb/src/kernel/blocks/backup/Backup.cpp | 72 +++++++++++++------------ 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 04b5a00494c..ec5c7a5d588 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -859,20 +859,20 @@ Backup::execBACKUP_REQ(Signal* signal) if(getOwnNodeId() != getMasterNodeId()) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::IAmNotMaster); return; }//if if (m_diskless) { - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::CannotBackupDiskless); return; } if(dataLen32 != 0) { jam(); - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::BackupDefinitionNotImplemented); return; }//if @@ -887,7 +887,7 @@ Backup::execBACKUP_REQ(Signal* signal) c_backups.seize(ptr); if(ptr.i == RNIL) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::OutOfBackupRecord); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::OutOfBackupRecord); return; }//if @@ -936,23 +936,23 @@ void Backup::sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode) { jam(); - if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) - { - sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode); - } + sendBackupRef(ptr.p->clientRef, ptr.p->flags, signal, ptr.p->clientData, errorCode); cleanup(signal, ptr); } void -Backup::sendBackupRef(BlockReference senderRef, Signal *signal, +Backup::sendBackupRef(BlockReference senderRef, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode) { jam(); - BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); - ref->senderData = senderData; - ref->errorCode = errorCode; - ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); - sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + if (SEND_BACKUP_STARTED_FLAG(flags)) + { + BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); + ref->senderData = senderData; + ref->errorCode = errorCode; + ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); + sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + } if(errorCode != BackupRef::IAmNotMaster){ signal->theData[0] = EventReport::BackupFailedToStart; @@ -1204,12 +1204,12 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) */ CRASH_INSERTION((10034)); - BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); - conf->backupId = ptr.p->backupId; - conf->senderData = ptr.p->clientData; - conf->nodes = ptr.p->nodes; if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) { + BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); + conf->backupId = ptr.p->backupId; + conf->senderData = ptr.p->clientData; + conf->nodes = ptr.p->nodes; sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, BackupConf::SignalLength, JBB); } @@ -2094,18 +2094,18 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) if(!ptr.p->checkError()) { - BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->startGCP = ptr.p->startGCP; - rep->stopGCP = ptr.p->stopGCP; - rep->noOfBytes = ptr.p->noOfBytes; - rep->noOfRecords = ptr.p->noOfRecords; - rep->noOfLogBytes = ptr.p->noOfLogBytes; - rep->noOfLogRecords = ptr.p->noOfLogRecords; - rep->nodes = ptr.p->nodes; if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) { + BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->startGCP = ptr.p->startGCP; + rep->stopGCP = ptr.p->stopGCP; + rep->noOfBytes = ptr.p->noOfBytes; + rep->noOfRecords = ptr.p->noOfRecords; + rep->noOfLogBytes = ptr.p->noOfLogBytes; + rep->noOfLogRecords = ptr.p->noOfLogRecords; + rep->nodes = ptr.p->nodes; sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, BackupCompleteRep::SignalLength, JBB); } @@ -2146,12 +2146,12 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr) return; } - BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->reason = ptr.p->errorCode; if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) { + BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->reason = ptr.p->errorCode; sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, BackupAbortRep::SignalLength, JBB); } @@ -2286,7 +2286,13 @@ Backup::execDEFINE_BACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = req->clientRef; ptr.p->clientData = req->clientData; - ptr.p->flags = req->flags; + if(senderRef == reference()) + ptr.p->flags = req->flags; + else + ptr.p->flags = req->flags & ~((Uint32)0x3); /* remove waitCompleted flags + * as non master should never + * reply + */ ptr.p->masterRef = senderRef; ptr.p->nodes = req->nodes; ptr.p->backupId = backupId; From 9c5dd6a2338e6bb71b9d64cc03419f1d1eb86038 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 15:43:46 +0200 Subject: [PATCH 30/48] corrected printouts in backup test ndb/src/kernel/blocks/backup/Backup.hpp: missed this file in prev commit ndb/test/src/NdbBackup.cpp: corrected printouts in backup test --- ndb/src/kernel/blocks/backup/Backup.hpp | 2 +- ndb/test/src/NdbBackup.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index 7780d05ab9e..f3d180b9467 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -596,7 +596,7 @@ public: bool insertFileHeader(BackupFormat::FileType, BackupRecord*, BackupFile*); void sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode); - void sendBackupRef(BlockReference ref, Signal *signal, + void sendBackupRef(BlockReference ref, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode); void dumpUsedResources(); void cleanup(Signal*, BackupRecordPtr ptr); diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 28724323bd7..1e56db83c11 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -50,14 +50,17 @@ NdbBackup::start(unsigned int & _backup_id){ 2, // wait until completed &_backup_id, &reply) == -1) { - g_err << "Could not start backup " << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return -1; } if(reply.return_code != 0){ g_err << "PLEASE CHECK CODE NdbBackup.cpp line=" << __LINE__ << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return reply.return_code; } return 0; From 110230beeca54c76d142b184a35b08029fa3a91b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 16:47:27 +0200 Subject: [PATCH 31/48] corrected typo --- ndb/src/mgmsrv/MgmtSrvr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index e9d3ce19076..011643237f8 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -2506,6 +2506,7 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) #endif if (rep->failNo == nodeId || waitCompleted == 1) + return 1326; // wait for next signal // master node will report aborted backup break; From e61d56a985ad06d23548b367c6258b006ac2dfea Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 16:51:35 +0200 Subject: [PATCH 32/48] corrected type --- ndb/src/mgmsrv/MgmtSrvr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index aedddb62738..fae0941beb8 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -2526,6 +2526,7 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) #endif if (rep->failNo == nodeId || waitCompleted == 1) + return 1326; // wait for next signal // master node will report aborted backup break; From 824750a9edc0ec1c186d9afbdcdbbdcb7b0b7ac0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 18:51:36 +0400 Subject: [PATCH 33/48] Remove an obsolete comment and an unused variable. sql/sp_head.cc: Remove an obsolete comment (recursion in SP is disabled) sql/sql_select.h: Remove an unused variable. --- sql/sp_head.cc | 11 ----------- sql/sql_select.h | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 14956138cbf..dd14bd28f8f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1827,17 +1827,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->query_id= next_query_id(); VOID(pthread_mutex_unlock(&LOCK_thread_count)); - /* - FIXME. Resetting statement (and using it) is not reentrant, thus recursive - functions which try to use the same LEX twice will crash server. - We should prevent such situations by tracking if LEX is already - in use and throwing error about unallowed recursion if needed. - OTOH it is nice to allow recursion in cases when LEX is not really - used (e.g. in mathematical functions), so such tracking should be - implemented at the same time as ability not to store LEX for - instruction if it is not really used. - */ - if (thd->prelocked_mode == NON_PRELOCKED) { /* diff --git a/sql/sql_select.h b/sql/sql_select.h index 78fa88801be..47906c2697e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -230,7 +230,7 @@ class JOIN :public Sql_alloc /* Is set if we have a GROUP BY and we have ORDER BY on a constant. */ bool skip_sort_order; - bool need_tmp, hidden_group_fields, buffer_result; + bool need_tmp, hidden_group_fields; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value; List all_fields; // to store all fields that used in query @@ -299,8 +299,6 @@ class JOIN :public Sql_alloc skip_sort_order= 0; need_tmp= 0; hidden_group_fields= 0; /*safety*/ - buffer_result= test(select_options & OPTION_BUFFER_RESULT) && - !test(select_options & OPTION_FOUND_ROWS); error= 0; select= 0; return_tab= 0; From 1b15f430d6734bc3a3b1e4f5af6d52855ad7d33d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 18:25:42 +0200 Subject: [PATCH 34/48] fix for Bug #12849 Stored Procedure: Crash on procedure call with CHAR type 'INOUT' parameter (recommit with the right Bug#) mysql-test/r/sp.result: result file modified to reflect new test mysql-test/t/sp.test: added test for the bug sql/item.cc: protect Item_splocal value from modification by CONCAT() et al sql/item.h: added a buffer to save Item_splocal string pointer sql/sp_head.cc: don't employ reuse mechanism to save var into itself --- mysql-test/r/sp.result | 19 +++++++++++++++++++ mysql-test/t/sp.test | 26 ++++++++++++++++++++++++++ sql/item.cc | 19 ++++++++++++++++++- sql/item.h | 8 ++++++++ sql/sp_head.cc | 15 +++++++++++++-- 5 files changed, 84 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4424f4e6ad4..c3238860b40 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3193,4 +3193,23 @@ set f1= concat( 'hello', f1 ); return f1; end| drop function bug9048| +drop procedure if exists bug12849_1| +create procedure bug12849_1(inout x char) select x into x| +set @var='a'| +call bug12849_1(@var)| +select @var| +@var +a +drop procedure bug12849_1| +drop procedure if exists bug12849_2| +create procedure bug12849_2(inout foo varchar(15)) +begin +select concat(foo, foo) INTO foo; +end| +set @var='abcd'| +call bug12849_2(@var)| +select @var| +@var +abcdabcd +drop procedure bug12849_2| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index d52ebbbbf67..1fff6bf8109 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4043,6 +4043,32 @@ begin end| drop function bug9048| +# +# Bug #12849 Stored Procedure: Crash on procedure call with CHAR type +# 'INOUT' parameter +# + +--disable_warnings +drop procedure if exists bug12849_1| +--enable_warnings +create procedure bug12849_1(inout x char) select x into x| +set @var='a'| +call bug12849_1(@var)| +select @var| +drop procedure bug12849_1| + +--disable_warnings +drop procedure if exists bug12849_2| +--enable_warnings +create procedure bug12849_2(inout foo varchar(15)) +begin +select concat(foo, foo) INTO foo; +end| +set @var='abcd'| +call bug12849_2(@var)| +select @var| +drop procedure bug12849_2| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item.cc b/sql/item.cc index 56b03055968..e7da646ae73 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -818,8 +818,25 @@ String *Item_splocal::val_str(String *sp) DBUG_ASSERT(fixed); Item *it= this_item(); String *ret= it->val_str(sp); + /* + This way we mark returned value of val_str as const, + so that various functions (e.g. CONCAT) won't try to + modify the value of the Item. Analogous mechanism is + implemented for Item_param. + Without this trick Item_splocal could be changed as a + side-effect of expression computation. Here is an example + of what happens without it: suppose x is varchar local + variable in a SP with initial value 'ab' Then + select concat(x,'c'); + would change x's value to 'abc', as Item_func_concat::val_str() + would use x's internal buffer to compute the result. + This is intended behaviour of Item_func_concat. Comments to + Item_param class contain some more details on the topic. + */ + str_value_ptr.set(ret->ptr(), ret->length(), + ret->charset()); null_value= it->null_value; - return ret; + return &str_value_ptr; } diff --git a/sql/item.h b/sql/item.h index f128c72413d..381ba98e193 100644 --- a/sql/item.h +++ b/sql/item.h @@ -715,9 +715,17 @@ public: class Item_splocal : public Item { uint m_offset; + public: LEX_STRING m_name; + /* + Buffer, pointing to the string value of the item. We need it to + protect internal buffer from changes. See comment to analogous + member in Item_param for more details. + */ + String str_value_ptr; + /* Position of this reference to SP variable in the statement (the statement itself is in sp_instr_stmt::m_query). diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 14956138cbf..763d3ef3e0e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -275,8 +275,19 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, } DBUG_PRINT("info",("STRING_RESULT: %*s", s->length(), s->c_ptr_quick())); - CHARSET_INFO *itcs= it->collation.collation; - CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) Item_string(itcs), + /* + Reuse mechanism in sp_eval_func_item() is only employed for assignments + to local variables and OUT/INOUT SP parameters repsesented by + Item_splocal. Usually we have some expression, which needs + to be calculated and stored into the local variable. However in the + case if "it" equals to "reuse", there is no "calculation" step. So, + no reason to employ reuse mechanism to save variable into itself. + */ + if (it == reuse) + DBUG_RETURN(it); + + CREATE_ON_CALLERS_ARENA(it= new(reuse, &rsize) + Item_string(it->collation.collation), use_callers_arena, &backup_arena); /* We have to use special constructor and allocate string From 91d05c5234a3c507bcb6aac4cad6968afec34114 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 19:27:37 +0200 Subject: [PATCH 35/48] SignalSender.cpp: fixed compile error ndb/src/ndbapi/SignalSender.cpp: fixed compile error --- ndb/src/ndbapi/SignalSender.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp index 0a23529dc73..a1c80f22041 100644 --- a/ndb/src/ndbapi/SignalSender.cpp +++ b/ndb/src/ndbapi/SignalSender.cpp @@ -266,5 +266,5 @@ SignalSender::execNodeStatus(void* signalSender, template SimpleSignal* SignalSender::waitFor(unsigned, WaitForNode&); template SimpleSignal* SignalSender::waitFor(unsigned, WaitForAny&); -template Vector; +template class Vector; From f25716382447a3006408f9c1fa508f05dfce256b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 21:30:05 +0200 Subject: [PATCH 36/48] fix for bug #12651 (item of a prepared query allocated on non-permanent are thus dangling later) mysql-test/r/ps.result: test for bug #12651 (data allocated on thd's arena but not on permanent arena) mysql-test/t/ps.test: test for bug #12651 (data allocated on thd's arena but not on permanent arena) sql/sql_base.cc: if there is tree transformation then backup the current arena and use permanent one (for PS) otherwise the data will be deallocated after the prepare process is finished. this bug was introduced with the recent natural join patch --- mysql-test/r/ps.result | 8 ++++++++ mysql-test/t/ps.test | 15 +++++++++++++++ sql/sql_base.cc | 17 +++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index dc78f8d04ea..f1c3672083d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -773,6 +773,14 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp select ? from t1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1 drop table t1; +CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; +CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; +CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; +PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; +EXECUTE b12651; +1 +DROP VIEW b12651_V1; +DROP TABLE b12651_T1, b12651_T2; prepare stmt from "select @@time_zone"; execute stmt; @@time_zone diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 94596fbbc0e..94ee2b1ca39 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -809,6 +809,21 @@ select ??; select ? from t1; --enable_ps_protocol drop table t1; + +# +# Bug#12651 +# (Crash on a PS including a subquery which is a select from a simple view) +# +CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; +CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; +CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; + +PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; +EXECUTE b12651; + +DROP VIEW b12651_V1; +DROP TABLE b12651_T1, b12651_T2; + # # Bug#9359 "Prepared statements take snapshot of system vars at PREPARE # time" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7025568a1c8..3dce47cd9cf 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2612,6 +2612,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); Field_iterator_view field_it; field_it.set(table_list); + Query_arena *arena, backup; + DBUG_ASSERT(table_list->schema_table_reformed || (ref != 0 && table_list->view != 0)); for (; !field_it.end_of_fields(); field_it.next()) @@ -2633,7 +2635,13 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, name, length)) DBUG_RETURN(WRONG_GRANT); #endif + // in PS use own arena or data will be freed after prepare + if (register_tree_change) + arena= thd->activate_stmt_arena_if_needed(&backup); Item *item= field_it.create_item(thd); + if (register_tree_change && arena) + thd->restore_active_arena(arena, &backup); + if (!item) DBUG_RETURN(0); /* @@ -2695,6 +2703,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, field_it(*(table_ref->join_columns)); Natural_join_column *nj_col; Field *found_field; + Query_arena *arena, backup; + DBUG_ENTER("find_field_in_natural_join"); DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx", name, (ulong) ref)); @@ -2723,7 +2733,14 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, The found field is a view field, we do as in find_field_in_view() and return a pointer to pointer to the Item of that field. */ + if (register_tree_change) + arena= thd->activate_stmt_arena_if_needed(&backup); + Item *item= nj_col->create_item(thd); + + if (register_tree_change && arena) + thd->restore_active_arena(arena, &backup); + if (!item) DBUG_RETURN(NULL); DBUG_ASSERT(nj_col->table_field == NULL); From 91d2150dd69ce62f7aef3cc2855ddb975cde82da Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 12:37:16 -0700 Subject: [PATCH 37/48] sql_select.cc: Fixed bug #12885. Forced inheritence of the maybe_null flag for the expressions containing GROUP BY attributes in selects with ROLLUP. olap.test, olap.result: Added test case for bug #12885. mysql-test/r/olap.result: Added test case for bug #12885. mysql-test/t/olap.test: Added test case for bug #12885. sql/sql_select.cc: Fixed bug #12885. Forced inheritence of the maybe_null flag for the expressions containing GROUP BY attributes in selects with ROLLUP. --- mysql-test/r/olap.result | 13 +++++++++++++ mysql-test/t/olap.test | 13 +++++++++++++ sql/sql_select.cc | 17 ++++++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 7178895cf80..65f7c649624 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -516,3 +516,16 @@ a b c count 1 NULL NULL 2 NULL NULL NULL 2 DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a a + 1 COUNT(*) +1 2 1 +2 3 1 +NULL NULL 2 +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index c9a16b897c6..76c62d14621 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -250,4 +250,17 @@ SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; DROP TABLE t1; +# +# Bug #11885: derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e7af2a1aa75..3de546fd619 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9277,6 +9277,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate functions. + The function also corrects value of the the maybe_null attribute + for the items of all subexpressions containing group by fields. IMPLEMENTATION The function recursively traverses the tree of the expr expression, @@ -9287,6 +9289,9 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) This substitution is needed GROUP BY queries with ROLLUP if SELECT list contains expressions over group by attributes. + TODO: Some functions are not null-preserving. For those functions + updating of the maybe_null attribute is an overkill. + EXAMPLES SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP @@ -9307,6 +9312,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, arg != arg_end; arg++) { Item *item= *arg; + bool arg_changed= FALSE; if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM) { ORDER *group_tmp; @@ -9318,15 +9324,20 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); - *changed= TRUE; + arg_changed= TRUE; } } } else if (item->type() == Item::FUNC_ITEM) { - if (change_group_ref(thd, (Item_func *) item, group_list, changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed)) return 1; } + if (arg_changed) + { + expr->maybe_null= 1; + *changed= TRUE; + } } } return 0; @@ -9389,7 +9400,7 @@ bool JOIN::rollup_init() } if (item->type() == Item::FUNC_ITEM) { - bool changed= 0; + bool changed= FALSE; if (change_group_ref(thd, (Item_func *) item, group_list, &changed)) return 1; /* From 1e5069703abf8e0ae5df69a811cdd38633f5291d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 13:45:49 -0700 Subject: [PATCH 38/48] Manual merge --- mysql-test/t/olap.test | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 76c62d14621..98dc3e5056b 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -2,6 +2,10 @@ drop table if exists t1,t2; --enable_warnings +set @sav_dpi= @@div_precision_increment; +set div_precision_increment= 5; +show variables like 'div_precision_increment'; + create table t1 (product varchar(32), country_id int not null, year int, profit int); insert into t1 values ( 'Computer', 2,2000, 1200), ( 'TV', 1, 1999, 150), @@ -153,6 +157,13 @@ SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT b, a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT b,a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + +ALTER TABLE t1 ADD COLUMN c INT; +SELECT a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT distinct a,b,sum(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; + DROP TABLE t1; # @@ -184,6 +195,7 @@ SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP; SELECT * FROM ( SELECT a, SUM(a) m FROM t1 GROUP BY a WITH ROLLUP ) t2; DROP TABLE t1; +set div_precision_increment= @sav_dpi; # # Tests for bug #7914: ROLLUP over expressions on temporary table @@ -264,3 +276,22 @@ SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; DROP TABLE t1; # End of 4.1 tests + +# +# Tests for bug #11639: ROLLUP over view executed through filesort +# + +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES + (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), + (6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; + +DROP VIEW v1; +DROP TABLE t1; + + From afbdcd413adf6ff5b15de0e9c5d332aecf66850e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 22:57:27 +0200 Subject: [PATCH 39/48] BUG#12695: Item_func_isnull::update_used_tables did not update const_item_cache --- mysql-test/r/group_by.result | 9 +++++++++ mysql-test/t/group_by.test | 10 ++++++++++ sql/item_cmpfunc.h | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 8287a042d60..4ad28091164 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -764,3 +764,12 @@ select date(left(f1+0,8)) from t1 group by 1; date(left(f1+0,8)) 2005-06-06 drop table t1; +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +max(f1) is null +0 +select sql_buffer_result max(f1)+1 from t1; +max(f1)+1 +3 +drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 815da66c717..f14fab2d30e 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -600,4 +600,14 @@ insert into t1 values('2005-06-06'); select date(left(f1+0,8)) from t1 group by 1; drop table t1; +# +# BUG#12695: Item_func_isnull::update_used_tables +# did not update const_item_cache +# +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +select sql_buffer_result max(f1)+1 from t1; +drop table t1; + # End of 4.1 tests diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..bb4759918ff 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -805,7 +805,7 @@ public: else { args[0]->update_used_tables(); - if (!(used_tables_cache=args[0]->used_tables())) + if ((const_item_cache= !(used_tables_cache= args[0]->used_tables()))) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) args[0]->is_null(); From 2b17f75073b378cffd927af49d2b4b0aeb7cd7be Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 02:01:04 +0400 Subject: [PATCH 40/48] Fix -ansi -pedantic compilation failure. --- ndb/src/ndbapi/SignalSender.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp index 0a23529dc73..ad95390f83b 100644 --- a/ndb/src/ndbapi/SignalSender.cpp +++ b/ndb/src/ndbapi/SignalSender.cpp @@ -266,5 +266,5 @@ SignalSender::execNodeStatus(void* signalSender, template SimpleSignal* SignalSender::waitFor(unsigned, WaitForNode&); template SimpleSignal* SignalSender::waitFor(unsigned, WaitForAny&); -template Vector; - +template class Vector; + From 2eaee052bc8456d315b58ce776f6f7c3b24a893f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 8 Sep 2005 15:45:31 -0700 Subject: [PATCH 41/48] olap.result, olap.test: Added a test case with VIEW for bug #12885. mysql-test/t/olap.test: Added a test case with VIEW for bug #12885. mysql-test/r/olap.result: Added a test case with VIEW for bug #12885. --- mysql-test/r/olap.result | 16 ++++++++++++++++ mysql-test/t/olap.test | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index b5b43cba3c7..df0ee09ea8e 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -602,3 +602,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +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 +COUNT(*) bigint(21) NO 0 +SELECT * FROM v1; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 98dc3e5056b..3a6a5e46f37 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -263,8 +263,8 @@ SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; DROP TABLE t1; # -# Bug #11885: derived table specified by a subquery with -# ROLLUP over expressions on not nullable group by attributes +# Bug #12885(1): derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes # CREATE TABLE t1 (a int(11) NOT NULL); @@ -294,4 +294,19 @@ EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; DROP VIEW v1; DROP TABLE t1; +# +# Bug #12885(2): view specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +CREATE VIEW v1 AS + SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +DESC v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; From f32088a94188f5baf4acea10067643d9352c6d23 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 11:43:26 +0400 Subject: [PATCH 42/48] Post-merge fixes. Call sp_cache_clear in THD::cleanup. --- sql/sql_class.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 4ed8d61a2be..975014b9780 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -383,8 +383,10 @@ void THD::cleanup(void) my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); + sp_cache_clear(&sp_proc_cache); - sp_cache_clear(&sp_func_cache); /*psergey: move to ~THD? */ + sp_cache_clear(&sp_func_cache); + if (global_read_lock) unlock_global_read_lock(this); if (ull) @@ -424,9 +426,6 @@ THD::~THD() ha_close_connection(this); - sp_cache_clear(&sp_proc_cache); - sp_cache_clear(&sp_func_cache); - DBUG_PRINT("info", ("freeing host")); if (host != my_localhost) // If not pointer to constant safeFree(host); From acf8d0f4d0f6e704960f2ffc9b03b61ba6c9c831 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 13:22:16 +0500 Subject: [PATCH 43/48] Bug#12817 SHOW STATUS now blob fields This fix is cancellation of ChangeSet 1.2329 05/07/12 08:35:30 reggie@linux.site +8 -0 Bug 7142 Show Fields from fails using Borland's dbExpress interface The reason is we can't fix bug#7142 without breaking of existing applications/APIs that worked fine with earlier 4.1 bug 7142 is fixed in 5.0 mysql-test/r/ps_1general.result: Bug #12817 SHOW STATUS now blob fields mysql-test/r/ps_2myisam.result: Bug #12817 SHOW STATUS now blob fields mysql-test/r/ps_3innodb.result: Bug #12817 SHOW STATUS now blob fields mysql-test/r/ps_4heap.result: Bug #12817 SHOW STATUS now blob fields mysql-test/r/ps_5merge.result: Bug #12817 SHOW STATUS now blob fields sql/item.cc: Bug #12817 SHOW STATUS now blob fields sql/sql_show.cc: Bug #12817 SHOW STATUS now blob fields tests/mysql_client_test.c: Bug #12817 SHOW STATUS now blob fields --- mysql-test/r/ps_1general.result | 12 ++++++------ mysql-test/r/ps_2myisam.result | 6 +++--- mysql-test/r/ps_3innodb.result | 6 +++--- mysql-test/r/ps_4heap.result | 6 +++--- mysql-test/r/ps_5merge.result | 12 ++++++------ sql/item.cc | 9 +-------- sql/sql_show.cc | 34 +-------------------------------- tests/mysql_client_test.c | 6 +++--- 8 files changed, 26 insertions(+), 65 deletions(-) diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index c4ccdf9eb34..49e858eca56 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -470,12 +470,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 14 N 1 31 8 +def Extra 253 255 14 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort SET @arg00=1 ; @@ -486,12 +486,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 5 Y 0 31 8 -def possible_keys 252 4096 7 Y 0 31 8 +def possible_keys 253 4096 7 Y 0 31 8 def key 253 64 7 Y 0 31 8 def key_len 8 3 1 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 27 N 1 31 8 +def Extra 253 255 27 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using filesort drop table if exists t2; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 6ef61b05577..4b655cfb854 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 drop table if exists t2 ; diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 96047ac3182..4d2a62887d6 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index bff4b6a5ad8..a4919b664c4 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1154,12 +1154,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 5ed6c10a47c..f98cc1b3cdf 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1196,12 +1196,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence @@ -4210,12 +4210,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/sql/item.cc b/sql/item.cc index 7aaa678ddb0..010189c321c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1973,14 +1973,7 @@ void Item::make_field(Send_field *tmp_field) void Item_empty_string::make_field(Send_field *tmp_field) { - enum_field_types type = FIELD_TYPE_VAR_STRING; - if (max_length >= 16777216) - type = FIELD_TYPE_LONG_BLOB; - else if (max_length >= 65536) - type = FIELD_TYPE_MEDIUM_BLOB; - else if (max_length >= 256) - type = FIELD_TYPE_BLOB; - init_make_field(tmp_field, type); + init_make_field(tmp_field,FIELD_TYPE_VAR_STRING); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 647dfe2ac4d..7cefd89c23c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -638,33 +638,6 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) DBUG_RETURN(0); } -/* - returns the length of the longest type on the given table. - - This is used so that show fields will return the data using the proper - lengths instead of forcing columns such as type to always return with a - given length. -*/ - -uint get_longest_type_in_table(TABLE *table, const char *wild) -{ - Field **ptr,*field; - char tmp[MAX_FIELD_WIDTH]; - uint max_len= 0; - - for (ptr=table->field; (field= *ptr); ptr++) - { - if (!wild || !wild[0] || - !wild_case_compare(system_charset_info, field->field_name,wild)) - { - String type(tmp,sizeof(tmp), system_charset_info); - field->sql_type(type); - max_len= max(max_len, type.length()); - } - } - return max_len; -} - /*************************************************************************** ** List all columns in a table_list->real_name @@ -694,14 +667,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, #ifndef NO_EMBEDDED_ACCESS_CHECKS (void) get_table_grant(thd, table_list); #endif - - /* we scan for the longest since long enum types can exceed 40 */ - uint max_len = get_longest_type_in_table(table, wild); - List field_list; field_list.push_back(new Item_empty_string("Field",NAME_LEN)); - field_list.push_back(new Item_empty_string("Type", - max_len > 40 ? max_len : 40)); + field_list.push_back(new Item_empty_string("Type", 40)); if (verbose) field_list.push_back(new Item_empty_string("Collation",40)); field_list.push_back(new Item_empty_string("Null",1)); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index ffcf5b6f34d..eadbd37f8f6 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7182,7 +7182,7 @@ static void test_explain_bug() verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 10, 0); - verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*64, 0); verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, @@ -7195,13 +7195,13 @@ static void test_explain_bug() (mysql_get_server_version(mysql) <= 50000 ? 3 : 4096), 0); - verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*16, 0); verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, "", "", "", 10, 0); - verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, "", "", "", 255, 0); mysql_free_result(result); From fa3c6c76f2ce62ce042546320cf8f1fb517d2b54 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 12:57:00 +0400 Subject: [PATCH 44/48] Post-merge fixes --- mysql-test/r/group_by.result | 14 +++++++------- mysql-test/r/olap.result | 1 + mysql-test/t/group_by.test | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index bfde408343e..45dca86f5f7 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -751,13 +751,6 @@ COUNT(DISTINCT(t1.id)) comment 1 NULL 1 a problem DROP TABLE t1, t2; -create table t1 (f1 date); -insert into t1 values('2005-06-06'); -insert into t1 values('2005-06-06'); -select date(left(f1+0,8)) from t1 group by 1; -date(left(f1+0,8)) -2005-06-06 -drop table t1; create table t1(f1 varchar(5) key); insert into t1 values (1),(2); select sql_buffer_result max(f1) is null from t1; @@ -767,6 +760,13 @@ select sql_buffer_result max(f1)+1 from t1; max(f1)+1 3 drop table t1; +create table t1 (f1 date); +insert into t1 values('2005-06-06'); +insert into t1 values('2005-06-06'); +select date(left(f1+0,8)) from t1 group by 1; +date(left(f1+0,8)) +2005-06-06 +drop table t1; CREATE TABLE t1 (n int); INSERT INTO t1 VALUES (1); SELECT n+1 AS n FROM t1 GROUP BY n; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 73dd3fc8aa2..df0ee09ea8e 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -579,6 +579,7 @@ a LENGTH(a) COUNT(*) 1 1 1 2 1 1 NULL NULL 2 +DROP TABLE t1; CREATE TABLE t1(id int, type char(1)); INSERT INTO t1 VALUES (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 4631fad3352..df5535386a5 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -575,6 +575,12 @@ CREATE TABLE t1 (id varchar(20) NOT NULL); INSERT INTO t1 VALUES ('trans1'), ('trans2'); CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); INSERT INTO t2 VALUES ('trans1', 'a problem'); + +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment + FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; + +DROP TABLE t1, t2; + # # BUG#12695: Item_func_isnull::update_used_tables # did not update const_item_cache @@ -585,12 +591,6 @@ select sql_buffer_result max(f1) is null from t1; select sql_buffer_result max(f1)+1 from t1; drop table t1; -SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment - FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; - -DROP TABLE t1, t2; - - # # Bug #12266 GROUP BY expression on DATE column produces result with # reduced length From ec16a3d6be59b8817eeb217b429d5b1afeecfd2b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 12:15:25 +0200 Subject: [PATCH 45/48] aftermerge --- mysql-test/r/group_by.result | 16 ++++++++-------- mysql-test/t/group_by.test | 10 ---------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index bfde408343e..7bc886022cc 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -758,6 +758,14 @@ select date(left(f1+0,8)) from t1 group by 1; date(left(f1+0,8)) 2005-06-06 drop table t1; +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +n +2 +Warnings: +Warning 1052 Column 'n' in group statement is ambiguous +DROP TABLE t1; create table t1(f1 varchar(5) key); insert into t1 values (1),(2); select sql_buffer_result max(f1) is null from t1; @@ -767,14 +775,6 @@ select sql_buffer_result max(f1)+1 from t1; max(f1)+1 3 drop table t1; -CREATE TABLE t1 (n int); -INSERT INTO t1 VALUES (1); -SELECT n+1 AS n FROM t1 GROUP BY n; -n -2 -Warnings: -Warning 1052 Column 'n' in group statement is ambiguous -DROP TABLE t1; create table t1 (c1 char(3), c2 char(3)); create table t2 (c3 char(3), c4 char(3)); insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 043adb97c64..60b6ced9d6a 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -575,16 +575,6 @@ CREATE TABLE t1 (id varchar(20) NOT NULL); INSERT INTO t1 VALUES ('trans1'), ('trans2'); CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); INSERT INTO t2 VALUES ('trans1', 'a problem'); -# -# BUG#12695: Item_func_isnull::update_used_tables -# did not update const_item_cache -# -create table t1(f1 varchar(5) key); -insert into t1 values (1),(2); -select sql_buffer_result max(f1) is null from t1; -select sql_buffer_result max(f1)+1 from t1; -drop table t1; - SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; From 708553e0693c678ad32e5f5793a8e28823cc5627 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 12:47:57 +0200 Subject: [PATCH 46/48] aftermerge --- mysql-test/r/group_by.result | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 45dca86f5f7..7bc886022cc 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -751,15 +751,6 @@ COUNT(DISTINCT(t1.id)) comment 1 NULL 1 a problem DROP TABLE t1, t2; -create table t1(f1 varchar(5) key); -insert into t1 values (1),(2); -select sql_buffer_result max(f1) is null from t1; -max(f1) is null -0 -select sql_buffer_result max(f1)+1 from t1; -max(f1)+1 -3 -drop table t1; create table t1 (f1 date); insert into t1 values('2005-06-06'); insert into t1 values('2005-06-06'); @@ -775,6 +766,15 @@ n Warnings: Warning 1052 Column 'n' in group statement is ambiguous DROP TABLE t1; +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +max(f1) is null +0 +select sql_buffer_result max(f1)+1 from t1; +max(f1)+1 +3 +drop table t1; create table t1 (c1 char(3), c2 char(3)); create table t2 (c3 char(3), c4 char(3)); insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); From 42a433853fa28c7f81618f441c88215261b19f24 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 16:23:12 +0400 Subject: [PATCH 47/48] Comment why lex->result is ignored if EXPLAIN --- sql/sql_parse.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 31582e7b2f4..5d0070667c2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2438,6 +2438,12 @@ mysql_execute_command(THD *thd) { if (lex->describe) { + /* + We always use select_send for EXPLAIN, even if it's an EXPLAIN + for SELECT ... INTO OUTFILE: a user application should be able + to prepend EXPLAIN to any query and receive output for it, + even if the query itself redirects the output. + */ if (!(result= new select_send())) goto error; else From 27eeeab84423f3f46ffa3e73e29fe30fc35570e0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Sep 2005 17:51:13 +0500 Subject: [PATCH 48/48] after merge fix --- mysql-test/r/ps_1general.result | 3 +-- mysql-test/r/ps_2myisam.result | 2 +- mysql-test/r/ps_3innodb.result | 2 +- mysql-test/r/ps_4heap.result | 2 +- mysql-test/r/ps_5merge.result | 4 ++-- sql/item.cc | 7 ++++++- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index aeb1f7f653b..7fb1e1b4df4 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -491,8 +491,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 5 Y 0 31 8 def possible_keys 253 4096 7 Y 0 31 8 def key 253 64 7 Y 0 31 8 -def key_len 8 3 1 Y 32928 0 63 - +def key_len 253 4096 1 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 27 N 1 31 8 diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index ee22ff2025c..16ead200933 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1156,7 +1156,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 -def key_len 8 3 0 Y 32928 0 63 +def key_len 253 4096 0 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index abd57ef9e80..9ab5a79f755 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1156,7 +1156,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 -def key_len 8 3 0 Y 32928 0 63 +def key_len 253 4096 0 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index a52c1118d2c..8336a5bf99b 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1157,7 +1157,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 -def key_len 8 3 0 Y 32928 0 63 +def key_len 253 4096 0 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index d73ae8d6d63..f341247a417 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1199,7 +1199,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 -def key_len 8 3 0 Y 32928 0 63 +def key_len 253 4096 0 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 @@ -4211,7 +4211,7 @@ def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 -def key_len 8 3 0 Y 32928 0 63 +def key_len 253 4096 0 Y 128 31 63 def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 def Extra 253 255 0 N 1 31 8 diff --git a/sql/item.cc b/sql/item.cc index 4023a551c19..e7da646ae73 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3627,7 +3627,12 @@ void Item::make_field(Send_field *tmp_field) void Item_empty_string::make_field(Send_field *tmp_field) { - init_make_field(tmp_field,FIELD_TYPE_VAR_STRING); + enum_field_types type= FIELD_TYPE_VAR_STRING; + if (max_length >= 16777216) + type= FIELD_TYPE_LONG_BLOB; + else if (max_length >= 65536) + type= FIELD_TYPE_MEDIUM_BLOB; + init_make_field(tmp_field, type); }