diff options
66 files changed, 1937 insertions, 395 deletions
diff --git a/configure.in b/configure.in index 19dda37cfd8..1346a87c35a 100644 --- a/configure.in +++ b/configure.in @@ -1727,6 +1727,30 @@ case "$with_atomic_ops" in *) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;; esac +AC_CACHE_CHECK([whether the compiler provides atomic builtins], + [mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([ + int main() + { + int foo= -10; int bar= 10; + if (!__sync_fetch_and_add(&foo, bar) || foo) + return -1; + bar= __sync_lock_test_and_set(&foo, bar); + if (bar || foo != 10) + return -1; + bar= __sync_val_compare_and_swap(&bar, foo, 15); + if (bar) + return -1; + return 0; + } +], [mysql_cv_gcc_atomic_builtins=yes], + [mysql_cv_gcc_atomic_builtins=no], + [mysql_cv_gcc_atomic_builtins=no])]) + +if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then + AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1, + [Define to 1 if compiler provides atomic builtins.]) +fi + # Force static compilation to avoid linking problems/get more speed AC_ARG_WITH(mysqld-ldflags, [ --with-mysqld-ldflags Extra linking arguments for mysqld], diff --git a/include/Makefile.am b/include/Makefile.am index 8335da36e93..5975a3e8bf0 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -36,7 +36,7 @@ noinst_HEADERS = config-win.h config-netware.h \ mysql_version.h.in my_handler.h my_time.h \ my_vle.h my_user.h my_atomic.h atomic/nolock.h \ atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \ - my_libwrap.h + atomic/gcc_builtins.h my_libwrap.h # Remove built files and the symlinked directories CLEANFILES = $(BUILT_SOURCES) readline openssl diff --git a/include/atomic/gcc_builtins.h b/include/atomic/gcc_builtins.h new file mode 100644 index 00000000000..509701b30a5 --- /dev/null +++ b/include/atomic/gcc_builtins.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2008 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; version 2 of the License. + + 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 */ + +#define make_atomic_add_body(S) \ + v= __sync_fetch_and_add(a, v); +#define make_atomic_swap_body(S) \ + v= __sync_lock_test_and_set(a, v); +#define make_atomic_cas_body(S) \ + int ## S sav; \ + sav= __sync_val_compare_and_swap(a, *cmp, set); \ + if (!(ret= (sav == *cmp))) *cmp= sav; + +#ifdef MY_ATOMIC_MODE_DUMMY +#define make_atomic_load_body(S) ret= *a +#define make_atomic_store_body(S) *a= v +#else +#define make_atomic_load_body(S) \ + ret= __sync_fetch_and_or(a, 0); +#define make_atomic_store_body(S) \ + (void) __sync_lock_test_and_set(a, v); +#endif diff --git a/include/atomic/nolock.h b/include/atomic/nolock.h index f15c8b13b7f..10ac17884b6 100644 --- a/include/atomic/nolock.h +++ b/include/atomic/nolock.h @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#if defined(__i386__) || defined(_M_IX86) +#if defined(__i386__) || defined(_M_IX86) || defined(HAVE_GCC_ATOMIC_BUILTINS) #ifdef MY_ATOMIC_MODE_DUMMY # define LOCK "" @@ -21,7 +21,9 @@ # define LOCK "lock" #endif -#ifdef __GNUC__ +#ifdef HAVE_GCC_ATOMIC_BUILTINS +#include "gcc_builtins.h" +#elif __GNUC__ #include "x86-gcc.h" #elif defined(_MSC_VER) #include "x86-msvc.h" diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test index efca53d5698..5abd04b98ef 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test @@ -419,7 +419,7 @@ connection master; update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; - update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; + update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; --echo --echo ** Delete from Master ** diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 3005e67935b..703dfa44df0 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -723,20 +723,6 @@ set @@sort_buffer_size=default; DROP TABLE t1,t2; -# -# Bug #32815: query with ORDER BY and a possible ref_or_null access -# - -CREATE TABLE t1 (id int, type char(6), d int, INDEX idx(id,d)) ENGINE=InnoDB; -INSERT INTO t1 VALUES - (191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); - -EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; -SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; - -DROP TABLE t1; - - # Test of behaviour with CREATE ... SELECT # @@ -1091,6 +1077,19 @@ desc t1; show create table t1; drop table t1; +# +# Bug #32815: query with ORDER BY and a possible ref_or_null access +# + +CREATE TABLE t1 (id int, type char(6), d int, INDEX idx(id,d)) ENGINE=InnoDB; +INSERT INTO t1 VALUES + (191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); + +EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; +SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; + +DROP TABLE t1; + --echo End of 5.0 tests # Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY @@ -1383,4 +1382,32 @@ create table t1 (a int auto_increment primary key) engine=innodb; alter table t1 order by a; drop table t1; +# +# Bug #33697: ORDER BY primary key DESC vs. ref access + filesort +# (reproduced only with InnoDB tables) +# + +CREATE TABLE t1 + (vid integer NOT NULL, + tid integer NOT NULL, + idx integer NOT NULL, + name varchar(128) NOT NULL, + type varchar(128) NULL, + PRIMARY KEY(idx, vid, tid), + UNIQUE(vid, tid, name) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES + (1,1,1,'pk',NULL),(2,1,1,'pk',NULL),(3,1,1,'pk',NULL),(4,1,1,'c1',NULL), + (5,1,1,'pk',NULL),(1,1,2,'c1',NULL),(2,1,2,'c1',NULL),(3,1,2,'c1',NULL), + (4,1,2,'c2',NULL),(5,1,2,'c1',NULL),(2,1,3,'c2',NULL),(3,1,3,'c2',NULL), + (4,1,3,'pk',NULL),(5,1,3,'c2',NULL), + (2,1,4,'c_extra',NULL),(3,1,4,'c_extra',NULL); + +EXPLAIN SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; + +SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; + +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/include/ps_modify.inc b/mysql-test/include/ps_modify.inc index f66f888261d..4cde18b97d1 100644 --- a/mysql-test/include/ps_modify.inc +++ b/mysql-test/include/ps_modify.inc @@ -108,6 +108,7 @@ execute stmt1 using @arg00, @arg01; select a,b from t1 where a=@arg00; set @arg00=NULL; set @arg01=2; +--error 1048 execute stmt1 using @arg00, @arg01; select a,b from t1 order by a; set @arg00=0; diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 54c2df34a7f..bc9daf43f14 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -231,8 +231,7 @@ a b 204 7 delete from t1 where a=0; update t1 set a=NULL where b=6; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null update t1 set a=300 where b=7; SET SQL_MODE=''; insert into t1(a,b)values(NULL,8); @@ -247,7 +246,7 @@ a b 1 1 200 2 201 4 -0 6 +203 6 300 7 301 8 400 9 @@ -263,6 +262,7 @@ a b 1 1 200 2 201 4 +203 6 300 7 301 8 400 9 @@ -273,20 +273,20 @@ a b 405 14 delete from t1 where a=0; update t1 set a=NULL where b=13; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null update t1 set a=500 where b=14; select * from t1 order by b; a b 1 1 200 2 201 4 +203 6 300 7 301 8 400 9 401 10 402 11 -0 13 +404 13 500 14 drop table t1; create table t1 (a bigint); diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 1472fdfdd7a..268f290ddca 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1478,3 +1478,39 @@ NULL 1 2 DROP TABLE t1; +CREATE TABLE t1 ( a INT, b INT ); +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; +c (SELECT a FROM t1 WHERE b = c) +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; +c (SELECT a FROM t1 WHERE b = c) +SELECT MAX(b) c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; +ERROR 42S22: Reference 'c' not supported (reference to group function) +SET @old_sql_mode = @@sql_mode; +SET @@sql_mode='ONLY_FULL_GROUP_BY'; +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; +c (SELECT a FROM t1 WHERE b = c) +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; +ERROR 42000: non-grouping field 'b' is used in HAVING clause +SELECT MAX(b) c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; +ERROR 42S22: Reference 'c' not supported (reference to group function) +INSERT INTO t1 VALUES (1, 1); +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; +c (SELECT a FROM t1 WHERE b = c) +1 1 +INSERT INTO t1 VALUES (2, 1); +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; +SET @@sql_mode = @old_sql_mode; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 87cf1acc10c..e9f00a667c0 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1349,7 +1349,7 @@ INSERT INTO t1 VALUES (191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL idx NULL NULL NULL 3 Using where; Using filesort +1 SIMPLE t1 ALL idx NULL NULL NULL 4 Using where; Using filesort SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; id type d 191 member 1 @@ -1609,4 +1609,29 @@ alter table t1 order by a; Warnings: Warning 1105 ORDER BY ignored as there is a user-defined clustered index in the table 't1' drop table t1; +CREATE TABLE t1 +(vid integer NOT NULL, +tid integer NOT NULL, +idx integer NOT NULL, +name varchar(128) NOT NULL, +type varchar(128) NULL, +PRIMARY KEY(idx, vid, tid), +UNIQUE(vid, tid, name) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1,1,1,'pk',NULL),(2,1,1,'pk',NULL),(3,1,1,'pk',NULL),(4,1,1,'c1',NULL), +(5,1,1,'pk',NULL),(1,1,2,'c1',NULL),(2,1,2,'c1',NULL),(3,1,2,'c1',NULL), +(4,1,2,'c2',NULL),(5,1,2,'c1',NULL),(2,1,3,'c2',NULL),(3,1,3,'c2',NULL), +(4,1,3,'pk',NULL),(5,1,3,'c2',NULL), +(2,1,4,'c_extra',NULL),(3,1,4,'c_extra',NULL); +EXPLAIN SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index vid PRIMARY 12 NULL 16 Using where +SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; +vid tid idx name type +3 1 4 c_extra NULL +3 1 3 c2 NULL +3 1 2 c1 NULL +3 1 1 pk NULL +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 345c9b07b98..5a2ebc37cc8 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -93,11 +93,9 @@ INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55"; Warnings: Warning 1265 Data truncated for column 'd' at row 1 UPDATE t1 SET d=1/NULL; -Warnings: -Warning 1265 Data truncated for column 'd' at row 1 +ERROR 23000: Column 'd' cannot be null UPDATE t1 SET d=NULL; -Warnings: -Warning 1048 Column 'd' cannot be null +ERROR 23000: Column 'd' cannot be null INSERT INTO t1 (a) values (null); ERROR 23000: Column 'a' cannot be null INSERT INTO t1 (a) values (1/null); @@ -132,7 +130,7 @@ Warning 1048 Column 'd' cannot be null Warning 1048 Column 'd' cannot be null select * from t1; a b c d - 0 0000-00-00 00:00:00 0 + 0 0000-00-00 00:00:00 2003 0 0000-00-00 00:00:00 0 0 0000-00-00 00:00:00 0 0 0000-00-00 00:00:00 0 diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result index ef53f227ec0..e10bcba36c2 100644 --- a/mysql-test/r/parser.result +++ b/mysql-test/r/parser.result @@ -527,3 +527,23 @@ SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1; a b 3 1998-01-01 00:00:00 DROP TABLE t1; +DROP TABLE IF EXISTS t1,t2,t3; +CREATE TABLE t1 (a1 INT, a2 INT, a3 INT, a4 DATETIME); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +SELECT t1.* FROM t1 AS t0, { OJ t2 INNER JOIN t1 ON (t1.a1=t2.a1) } WHERE t0.a3=2; +a1 a2 a3 a4 +SELECT t1.*,t2.* FROM { OJ ((t1 INNER JOIN t2 ON (t1.a1=t2.a2)) LEFT OUTER JOIN t3 ON t3.a3=t2.a1)}; +a1 a2 a3 a4 a1 a2 a3 a4 +SELECT t1.*,t2.* FROM { OJ ((t1 LEFT OUTER JOIN t2 ON t1.a3=t2.a2) INNER JOIN t3 ON (t3.a1=t2.a2))}; +a1 a2 a3 a4 a1 a2 a3 a4 +SELECT t1.*,t2.* FROM { OJ (t1 LEFT OUTER JOIN t2 ON t1.a1=t2.a2) CROSS JOIN t3 ON (t3.a2=t2.a3)}; +a1 a2 a3 a4 a1 a2 a3 a4 +SELECT * FROM {oj t1 LEFT OUTER JOIN t2 ON t1.a1=t2.a3} WHERE t1.a2 > 10; +a1 a2 a3 a4 a1 a2 a3 a4 +SELECT {fn CONCAT(a1,a2)} FROM t1; +{fn CONCAT(a1,a2)} +UPDATE t3 SET a4={d '1789-07-14'} WHERE a1=0; +SELECT a1, a4 FROM t2 WHERE a4 LIKE {fn UCASE('1789-07-14')}; +a1 a4 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index fbc6781e5e7..06bfd78a351 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1303,12 +1303,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index fcd0b5de9a0..f56b1d37a2c 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1286,12 +1286,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 862c0ff75c1..0c643facf72 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1287,12 +1287,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 51393cc8bc3..bd3cd4ac1fc 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1329,12 +1329,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; @@ -4351,12 +4350,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; diff --git a/mysql-test/r/query_cache_debug.result b/mysql-test/r/query_cache_debug.result new file mode 100644 index 00000000000..f177bfac836 --- /dev/null +++ b/mysql-test/r/query_cache_debug.result @@ -0,0 +1,24 @@ +flush status; +set query_cache_type=DEMAND; +set global query_cache_size= 1024*1024*512; +drop table if exists t1; +create table t1 (a varchar(100)); +insert into t1 values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); +Activate debug hook and attempt to retrieve the statement from the cache. +set session debug='+d,wait_in_query_cache_insert'; +select SQL_CACHE * from t1;; +On a second connection; clear the query cache. +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 1 +set global query_cache_size= 0; +Signal the debug hook to release the lock. +select id from information_schema.processlist where state='wait_in_query_cache_insert' into @thread_id; +kill query @thread_id; +Show query cache status. +show status like 'Qcache_queries_in_cache'; +Variable_name Value +Qcache_queries_in_cache 0 +set global query_cache_size= 0; +use test; +drop table t1; diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index 018173e723d..ca5c5b42102 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -733,6 +733,115 @@ optimizer: keep hreturn drop table t1; drop procedure proc_26977_broken; drop procedure proc_26977_works; +drop procedure if exists proc_33618_h; +drop procedure if exists proc_33618_c; +create procedure proc_33618_h(num int) +begin +declare count1 int default '0'; +declare vb varchar(30); +declare last_row int; +while(num>=1) do +set num=num-1; +begin +declare cur1 cursor for select `a` from t_33618; +declare continue handler for not found set last_row = 1; +set last_row:=0; +open cur1; +rep1: +repeat +begin +declare exit handler for 1062 begin end; +fetch cur1 into vb; +if (last_row = 1) then +## should generate a hpop instruction here +leave rep1; +end if; +end; +until last_row=1 +end repeat; +close cur1; +end; +end while; +end// +create procedure proc_33618_c(num int) +begin +declare count1 int default '0'; +declare vb varchar(30); +declare last_row int; +while(num>=1) do +set num=num-1; +begin +declare cur1 cursor for select `a` from t_33618; +declare continue handler for not found set last_row = 1; +set last_row:=0; +open cur1; +rep1: +repeat +begin +declare cur2 cursor for select `b` from t_33618; +fetch cur1 into vb; +if (last_row = 1) then +## should generate a cpop instruction here +leave rep1; +end if; +end; +until last_row=1 +end repeat; +close cur1; +end; +end while; +end// +show procedure code proc_33618_h; +Pos Instruction +0 set count1@1 _latin1'0' +1 set vb@2 NULL +2 set last_row@3 NULL +3 jump_if_not 24(24) (num@0 >= 1) +4 set num@0 (num@0 - 1) +5 cpush cur1@0 +6 hpush_jump 9 4 CONTINUE +7 set last_row@3 1 +8 hreturn 4 +9 set last_row@3 0 +10 copen cur1@0 +11 hpush_jump 13 4 EXIT +12 hreturn 0 17 +13 cfetch cur1@0 vb@2 +14 jump_if_not 17(17) (last_row@3 = 1) +15 hpop 1 +16 jump 19 +17 hpop 1 +18 jump_if_not 11(19) (last_row@3 = 1) +19 cclose cur1@0 +20 hpop 1 +21 cpop 1 +22 jump 3 +show procedure code proc_33618_c; +Pos Instruction +0 set count1@1 _latin1'0' +1 set vb@2 NULL +2 set last_row@3 NULL +3 jump_if_not 23(23) (num@0 >= 1) +4 set num@0 (num@0 - 1) +5 cpush cur1@0 +6 hpush_jump 9 4 CONTINUE +7 set last_row@3 1 +8 hreturn 4 +9 set last_row@3 0 +10 copen cur1@0 +11 cpush cur2@1 +12 cfetch cur1@0 vb@2 +13 jump_if_not 16(16) (last_row@3 = 1) +14 cpop 1 +15 jump 18 +16 cpop 1 +17 jump_if_not 11(18) (last_row@3 = 1) +18 cclose cur1@0 +19 hpop 1 +20 cpop 1 +21 jump 3 +drop procedure proc_33618_h; +drop procedure proc_33618_c; End of 5.0 tests. CREATE PROCEDURE p1() BEGIN diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index b81f8ea64c9..c33c378340e 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1579,3 +1579,51 @@ drop function f2; drop table t2; ERROR 42S02: Unknown table 't2' End of 5.1 tests +drop procedure if exists proc_33983_a; +drop procedure if exists proc_33983_b; +drop procedure if exists proc_33983_c; +drop procedure if exists proc_33983_d; +create procedure proc_33983_a() +begin +label1: +begin +label2: +begin +select 1; +end label1; +end; +end| +ERROR 42000: End-label label1 without match +create procedure proc_33983_b() +begin +label1: +repeat +label2: +repeat +select 1; +until FALSE end repeat label1; +until FALSE end repeat; +end| +ERROR 42000: End-label label1 without match +create procedure proc_33983_c() +begin +label1: +while TRUE do +label2: +while TRUE do +select 1; +end while label1; +end while; +end| +ERROR 42000: End-label label1 without match +create procedure proc_33983_d() +begin +label1: +loop +label2: +loop +select 1; +end loop label1; +end loop; +end| +ERROR 42000: End-label label1 without match diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 68aa278585f..50ece83b258 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6812,7 +6812,59 @@ DROP PROCEDURE db28318_b.t2; DROP DATABASE db28318_a; DROP DATABASE db28318_b; use test; -End of 5.0 tests +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS bug29770; +CREATE TABLE t1(a int); +CREATE PROCEDURE bug29770() +BEGIN +DECLARE CONTINUE HANDLER FOR SQLSTATE '42S22' SET @state:= 'run'; +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @exception:= 'run'; +SELECT x FROM t1; +END| +CALL bug29770(); +SELECT @state, @exception; +@state @exception +run NULL +DROP TABLE t1; +DROP PROCEDURE bug29770; +use test; +drop table if exists t_33618; +drop procedure if exists proc_33618; +create table t_33618 (`a` int, unique(`a`), `b` varchar(30)) engine=myisam; +insert into t_33618 (`a`,`b`) values (1,'1'),(2,'2'); +create procedure proc_33618(num int) +begin +declare count1 int default '0'; +declare vb varchar(30); +declare last_row int; +while(num>=1) do +set num=num-1; +begin +declare cur1 cursor for select `a` from t_33618; +declare continue handler for not found set last_row = 1; +set last_row:=0; +open cur1; +rep1: +repeat +begin +declare exit handler for 1062 begin end; +fetch cur1 into vb; +if (last_row = 1) then +leave rep1; +end if; +end; +until last_row=1 +end repeat; +close cur1; +end; +end while; +end// +call proc_33618(20); +drop table t_33618; +drop procedure proc_33618; +# ------------------------------------------------------------------ +# -- End of 5.0 tests +# ------------------------------------------------------------------ # # Bug#20550. @@ -6911,4 +6963,6 @@ END latin1 latin1_swedish_ci latin1_swedish_ci DROP FUNCTION f1; -End of 5.1 tests +# ------------------------------------------------------------------ +# -- End of 5.1 tests +# ------------------------------------------------------------------ diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 762457d57a6..20d44933128 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4291,6 +4291,54 @@ select count(*) from t1 where f12 = count(*) 3 drop table t1,t2; +CREATE TABLE t4 ( +f7 varchar(32) collate utf8_bin NOT NULL default '', +f10 varchar(32) collate utf8_bin default NULL, +PRIMARY KEY (f7) +); +INSERT INTO t4 VALUES(1,1), (2,null); +CREATE TABLE t2 ( +f4 varchar(32) collate utf8_bin NOT NULL default '', +f2 varchar(50) collate utf8_bin default NULL, +f3 varchar(10) collate utf8_bin default NULL, +PRIMARY KEY (f4), +UNIQUE KEY uk1 (f2) +); +INSERT INTO t2 VALUES(1,1,null), (2,2,null); +CREATE TABLE t1 ( +f8 varchar(32) collate utf8_bin NOT NULL default '', +f1 varchar(10) collate utf8_bin default NULL, +f9 varchar(32) collate utf8_bin default NULL, +PRIMARY KEY (f8) +); +INSERT INTO t1 VALUES (1,'P',1), (2,'P',1), (3,'R',2); +CREATE TABLE t3 ( +f6 varchar(32) collate utf8_bin NOT NULL default '', +f5 varchar(50) collate utf8_bin default NULL, +PRIMARY KEY (f6) +); +INSERT INTO t3 VALUES (1,null), (2,null); +SELECT +IF(t1.f1 = 'R', a1.f2, t2.f2) AS a4, +IF(t1.f1 = 'R', a1.f3, t2.f3) AS f3, +SUM( +IF( +(SELECT VPC.f2 +FROM t2 VPC, t4 a2, t2 a3 +WHERE +VPC.f4 = a2.f10 AND a3.f2 = a4 +LIMIT 1) IS NULL, +0, +t3.f5 +) +) AS a6 +FROM +t2, t3, t1 JOIN t2 a1 ON t1.f9 = a1.f4 +GROUP BY a4; +a4 f3 a6 +1 NULL NULL +2 NULL NULL +DROP TABLE t1, t2, t3, t4; End of 5.0 tests. CREATE TABLE t1 (a int, b int); INSERT INTO t1 VALUES (2,22),(1,11),(2,22); diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index a25ffc4c6fc..3e5f6a9b504 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -794,7 +794,7 @@ dps tinyint(3) unsigned default NULL INSERT INTO t1 VALUES (1.1325,3); SELECT ROUND(qty,3), dps, ROUND(qty,dps) FROM t1; ROUND(qty,3) dps ROUND(qty,dps) -1.133 3 1.133 +1.133 3 1.133000 DROP TABLE t1; SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS '%'; % @@ -885,4 +885,65 @@ c 1000 1234567890 DROP TABLE t1, t2, t3, t4; +CREATE TABLE t1( a DECIMAL(4, 3), b INT ); +INSERT INTO t1 VALUES ( 1, 5 ), ( 2, 4 ), ( 3, 3 ), ( 4, 2 ), ( 5, 1 ); +SELECT a, b, ROUND( a, b ) AS c FROM t1 ORDER BY c; +a b c +1.000 5 1.000 +2.000 4 2.000 +3.000 3 3.000 +4.000 2 4.000 +5.000 1 5.000 +SELECT a, b, ROUND( a, b ) AS c FROM t1 ORDER BY c DESC; +a b c +5.000 1 5.000 +4.000 2 4.000 +3.000 3 3.000 +2.000 4 2.000 +1.000 5 1.000 +CREATE TABLE t2 ( a INT, b INT, c DECIMAL(5, 4) ); +INSERT INTO t2 VALUES ( 0, 1, 1.2345 ), ( 1, 2, 1.2345 ), +( 3, 3, 1.2345 ), ( 2, 4, 1.2345 ); +SELECT a, b, MAX(ROUND(c, a)) +FROM t2 +GROUP BY a, b +ORDER BY b; +a b MAX(ROUND(c, a)) +0 1 1.0000 +1 2 1.2000 +3 3 1.2350 +2 4 1.2300 +SELECT a, b, ROUND(c, a) +FROM t2; +a b ROUND(c, a) +0 1 1.0000 +1 2 1.2000 +3 3 1.2350 +2 4 1.2300 +CREATE TABLE t3( a INT, b DECIMAL(6, 3) ); +INSERT INTO t3 VALUES( 0, 1.5 ); +SELECT ROUND( b, a ) FROM t3; +ROUND( b, a ) +2.000 +CREATE TABLE t4( a INT, b DECIMAL( 12, 0) ); +INSERT INTO t4 VALUES( -9, 1.5e9 ); +SELECT ROUND( b, a ) FROM t4; +ROUND( b, a ) +2000000000 +CREATE TABLE t5( a INT, b DECIMAL( 13, 12 ) ); +INSERT INTO t5 VALUES( 0, 1.5 ); +INSERT INTO t5 VALUES( 9, 1.5e-9 ); +SELECT ROUND( b, a ) FROM t5; +ROUND( b, a ) +2.000000000000 +0.000000002000 +CREATE TABLE t6( a INT ); +INSERT INTO t6 VALUES( 6 / 8 ); +SELECT * FROM t6; +a +1 +SELECT ROUND(20061108085411.000002); +ROUND(20061108085411.000002) +20061108085411 +DROP TABLE t1, t2, t3, t4, t5, t6; End of 5.0 tests diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 2971af7347d..09b997797b4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -3597,6 +3597,22 @@ DROP VIEW v1; DROP VIEW v2; DROP VIEW v3; DROP TABLE t1; +# +# Bug#29477: Not all fields of the target table were checked to have +# a default value when inserting into a view. +# +create table t1(f1 int, f2 int not null); +create view v1 as select f1 from t1; +insert into v1 values(1); +Warnings: +Warning 1423 Field of view 'test.v1' underlying table doesn't have a default value +set @old_mode=@@sql_mode; +set @@sql_mode=traditional; +insert into v1 values(1); +ERROR HY000: Field of view 'test.v1' underlying table doesn't have a default value +set @@sql_mode=@old_mode; +drop view v1; +drop table t1; End of 5.0 tests. DROP DATABASE IF EXISTS `d-1`; CREATE DATABASE `d-1`; diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index 2929328a9b1..249cd583345 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -98,8 +98,7 @@ Warning 1265 Data truncated for column 'c' at row 1 Warning 1265 Data truncated for column 'c' at row 2 alter table t1 add d char(2); update t1 set a=NULL where a=10; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null update t1 set c='mysql ab' where c='test'; Warnings: Warning 1265 Data truncated for column 'c' at row 4 diff --git a/mysql-test/suite/ndb/r/ps_7ndb.result b/mysql-test/suite/ndb/r/ps_7ndb.result index 6e2e61bbc5e..3cbc1a0e76f 100644 --- a/mysql-test/suite/ndb/r/ps_7ndb.result +++ b/mysql-test/suite/ndb/r/ps_7ndb.result @@ -1286,12 +1286,11 @@ a b set @arg00=NULL; set @arg01=2; execute stmt1 using @arg00, @arg01; -Warnings: -Warning 1048 Column 'a' cannot be null +ERROR 23000: Column 'a' cannot be null select a,b from t1 order by a; a b -0 two 1 one +2 two 3 three 4 four set @arg00=0; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index ad67f96db71..86648ba12c3 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result @@ -454,9 +454,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -1595,9 +1593,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -2736,9 +2732,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 8859a8e24e3..96d4ca237d1 100644 --- a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result @@ -454,9 +454,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -1595,9 +1593,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** @@ -2736,9 +2732,7 @@ f1 f2 f3 f4 update t31 set f5=555555555555555 where f3=6; update t31 set f2=2 where f3=2; update t31 set f1=NULL where f3=1; -update t31 set f3=NULL, f27=NULL, f35='f35 new value' where f3=3; -Warnings: -Warning 1048 Column 'f3' cannot be null +update t31 set f3=0, f27=NULL, f35='f35 new value' where f3=3; ** Delete from Master ** diff --git a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test index 4e06a6a7096..a36cfb11dae 100644 --- a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test +++ b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test @@ -49,7 +49,7 @@ kill @id; drop table t2,t3; insert into t4 values (3),(4); connection master; ---error 0,1053,2013 +--error 0,1053,2013,1048 reap; connection master1; save_master_pos; diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index 99e9b783d55..ff92c743960 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -149,6 +149,7 @@ delete from t1 where a=0; update t1 set a=0 where b=5; select * from t1 order by b; delete from t1 where a=0; +--error 1048 update t1 set a=NULL where b=6; update t1 set a=300 where b=7; SET SQL_MODE=''; @@ -164,6 +165,7 @@ delete from t1 where a=0; update t1 set a=0 where b=12; select * from t1 order by b; delete from t1 where a=0; +--error 1048 update t1 set a=NULL where b=13; update t1 set a=500 where b=14; select * from t1 order by b; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 94c2b463aaa..3211db5d6ed 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -790,8 +790,6 @@ drop table t1; SET SQL_MODE = ''; # - -# # Bug #32202: ORDER BY not working with GROUP BY # @@ -824,6 +822,7 @@ SELECT * FROM t1 GROUP BY c2 ORDER BY c2 DESC, c1 DESC; DROP TABLE t1; + --echo End of 5.0 tests # Bug #21174: Index degrades sort performance and # optimizer does not honor IGNORE INDEX. @@ -946,3 +945,51 @@ EXPLAIN SELECT b from t2 GROUP BY b; SELECT b from t2 GROUP BY b; DROP TABLE t1; + +# +# Bug #31797: error while parsing subqueries -- WHERE is parsed as HAVING +# +CREATE TABLE t1 ( a INT, b INT ); + +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; + +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; + +--error ER_ILLEGAL_REFERENCE +SELECT MAX(b) c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; + +SET @old_sql_mode = @@sql_mode; +SET @@sql_mode='ONLY_FULL_GROUP_BY'; + +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; + +--error ER_NON_GROUPING_FIELD_USED +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; + +--error ER_ILLEGAL_REFERENCE +SELECT MAX(b) c, (SELECT a FROM t1 WHERE b = c) +FROM t1 +HAVING b = 10; + +INSERT INTO t1 VALUES (1, 1); +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; + +INSERT INTO t1 VALUES (2, 1); +--error ER_SUBQUERY_NO_1_ROW +SELECT b c, (SELECT a FROM t1 WHERE b = c) +FROM t1; + +DROP TABLE t1; +SET @@sql_mode = @old_sql_mode; + + + diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 2878b54c357..ddf6b8870fa 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -61,7 +61,9 @@ drop table t1; # CREATE TABLE t1 (a varchar(16) NOT NULL default '', b smallint(6) NOT NULL default 0, c datetime NOT NULL default '0000-00-00 00:00:00', d smallint(6) NOT NULL default 0); INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55"; +--error 1048 UPDATE t1 SET d=1/NULL; +--error 1048 UPDATE t1 SET d=NULL; --error 1048 INSERT INTO t1 (a) values (null); diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test index 9170308a4f2..800d717cf6b 100644 --- a/mysql-test/t/parser.test +++ b/mysql-test/t/parser.test @@ -657,3 +657,23 @@ CREATE TABLE t1 (a INT, b DATETIME); INSERT INTO t1 VALUES (INTERVAL(3,2,1) + 1, "1997-12-31 23:59:59" + INTERVAL 1 SECOND); SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1; DROP TABLE t1; + +# +# Bug#28317 Left Outer Join with {oj outer-join} +# + +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3; +--enable_warnings +CREATE TABLE t1 (a1 INT, a2 INT, a3 INT, a4 DATETIME); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +SELECT t1.* FROM t1 AS t0, { OJ t2 INNER JOIN t1 ON (t1.a1=t2.a1) } WHERE t0.a3=2; +SELECT t1.*,t2.* FROM { OJ ((t1 INNER JOIN t2 ON (t1.a1=t2.a2)) LEFT OUTER JOIN t3 ON t3.a3=t2.a1)}; +SELECT t1.*,t2.* FROM { OJ ((t1 LEFT OUTER JOIN t2 ON t1.a3=t2.a2) INNER JOIN t3 ON (t3.a1=t2.a2))}; +SELECT t1.*,t2.* FROM { OJ (t1 LEFT OUTER JOIN t2 ON t1.a1=t2.a2) CROSS JOIN t3 ON (t3.a2=t2.a3)}; +SELECT * FROM {oj t1 LEFT OUTER JOIN t2 ON t1.a1=t2.a3} WHERE t1.a2 > 10; +SELECT {fn CONCAT(a1,a2)} FROM t1; +UPDATE t3 SET a4={d '1789-07-14'} WHERE a1=0; +SELECT a1, a4 FROM t2 WHERE a4 LIKE {fn UCASE('1789-07-14')}; +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 9e250372d51..771a32e8cd7 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1316,6 +1316,5 @@ SELECT 1 FROM t1 GROUP BY (SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1); DROP TABLE t1; - --echo End of 5.1 tests diff --git a/mysql-test/t/query_cache_debug.test b/mysql-test/t/query_cache_debug.test new file mode 100644 index 00000000000..b741eea0b29 --- /dev/null +++ b/mysql-test/t/query_cache_debug.test @@ -0,0 +1,46 @@ +--source include/not_embedded.inc +--source include/have_query_cache.inc +--source include/have_debug.inc + +# +# Bug #30887 Server crashes on SET GLOBAL query_cache_size=0 +# +flush status; +set query_cache_type=DEMAND; +set global query_cache_size= 1024*1024*512; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a varchar(100)); +insert into t1 values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); +connect (bug30887con1, localhost, root, ,test); +connect (bug30887con2, localhost, root, ,test); + +connection bug30887con1; +--echo Activate debug hook and attempt to retrieve the statement from the cache. +set session debug='+d,wait_in_query_cache_insert'; +--send select SQL_CACHE * from t1; + +connection default; +let $wait_condition= select count(*)= 1 from information_schema.processlist where state= 'wait_in_query_cache_insert'; +--source include/wait_condition.inc + +connection bug30887con2; +--echo On a second connection; clear the query cache. +show status like 'Qcache_queries_in_cache'; +set global query_cache_size= 0; + +connection default; +--echo Signal the debug hook to release the lock. +select id from information_schema.processlist where state='wait_in_query_cache_insert' into @thread_id; +kill query @thread_id; + +--echo Show query cache status. +show status like 'Qcache_queries_in_cache'; + +disconnect bug30887con1; +disconnect bug30887con2; +set global query_cache_size= 0; +use test; +drop table t1; + diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index 66d5323d2e2..84f0201c808 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -520,6 +520,83 @@ drop table t1; drop procedure proc_26977_broken; drop procedure proc_26977_works; +# +# Bug#33618 Crash in sp_rcontext +# + +--disable_warnings +drop procedure if exists proc_33618_h; +drop procedure if exists proc_33618_c; +--enable_warnings + +delimiter //; + +create procedure proc_33618_h(num int) +begin + declare count1 int default '0'; + declare vb varchar(30); + declare last_row int; + + while(num>=1) do + set num=num-1; + begin + declare cur1 cursor for select `a` from t_33618; + declare continue handler for not found set last_row = 1; + set last_row:=0; + open cur1; + rep1: + repeat + begin + declare exit handler for 1062 begin end; + fetch cur1 into vb; + if (last_row = 1) then + ## should generate a hpop instruction here + leave rep1; + end if; + end; + until last_row=1 + end repeat; + close cur1; + end; + end while; +end// + +create procedure proc_33618_c(num int) +begin + declare count1 int default '0'; + declare vb varchar(30); + declare last_row int; + + while(num>=1) do + set num=num-1; + begin + declare cur1 cursor for select `a` from t_33618; + declare continue handler for not found set last_row = 1; + set last_row:=0; + open cur1; + rep1: + repeat + begin + declare cur2 cursor for select `b` from t_33618; + fetch cur1 into vb; + if (last_row = 1) then + ## should generate a cpop instruction here + leave rep1; + end if; + end; + until last_row=1 + end repeat; + close cur1; + end; + end while; +end// +delimiter ;// + +show procedure code proc_33618_h; +show procedure code proc_33618_c; + +drop procedure proc_33618_h; +drop procedure proc_33618_c; --echo End of 5.0 tests. diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 606c2a673bc..286722df65c 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2306,6 +2306,69 @@ drop table t2; --echo End of 5.1 tests # +# Bug#33983 (Stored Procedures: wrong end <label> syntax is accepted) +# + +--disable_warnings +drop procedure if exists proc_33983_a; +drop procedure if exists proc_33983_b; +drop procedure if exists proc_33983_c; +drop procedure if exists proc_33983_d; +--enable_warnings + +delimiter |; + +--error ER_SP_LABEL_MISMATCH +create procedure proc_33983_a() +begin + label1: + begin + label2: + begin + select 1; + end label1; + end; +end| + +--error ER_SP_LABEL_MISMATCH +create procedure proc_33983_b() +begin + label1: + repeat + label2: + repeat + select 1; + until FALSE end repeat label1; + until FALSE end repeat; +end| + +--error ER_SP_LABEL_MISMATCH +create procedure proc_33983_c() +begin + label1: + while TRUE do + label2: + while TRUE do + select 1; + end while label1; + end while; +end| + +--error ER_SP_LABEL_MISMATCH +create procedure proc_33983_d() +begin + label1: + loop + label2: + loop + select 1; + end loop label1; + end loop; +end| + +delimiter ;| + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 004e1c4ddd2..6dc2f906d45 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -7902,7 +7902,86 @@ use test; ########################################################################### ---echo End of 5.0 tests +# +# Bug#29770 Two handlers are allowed to catch an error in an stored procedure. +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS bug29770; +--enable_warnings + +CREATE TABLE t1(a int); +delimiter |; +CREATE PROCEDURE bug29770() +BEGIN + DECLARE CONTINUE HANDLER FOR SQLSTATE '42S22' SET @state:= 'run'; + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @exception:= 'run'; + SELECT x FROM t1; +END| +delimiter ;| +CALL bug29770(); +SELECT @state, @exception; +DROP TABLE t1; +DROP PROCEDURE bug29770; + +# +# Bug#33618 Crash in sp_rcontext +# + +use test; + +--disable_warnings +drop table if exists t_33618; +drop procedure if exists proc_33618; +--enable_warnings + +create table t_33618 (`a` int, unique(`a`), `b` varchar(30)) engine=myisam; +insert into t_33618 (`a`,`b`) values (1,'1'),(2,'2'); + +delimiter //; + +create procedure proc_33618(num int) +begin + declare count1 int default '0'; + declare vb varchar(30); + declare last_row int; + + while(num>=1) do + set num=num-1; + begin + declare cur1 cursor for select `a` from t_33618; + declare continue handler for not found set last_row = 1; + set last_row:=0; + open cur1; + rep1: + repeat + begin + declare exit handler for 1062 begin end; + fetch cur1 into vb; + if (last_row = 1) then + leave rep1; + end if; + end; + until last_row=1 + end repeat; + close cur1; + end; + end while; +end// + +delimiter ;// + +call proc_33618(20); + +drop table t_33618; +drop procedure proc_33618; + +########################################################################### + +--echo # ------------------------------------------------------------------ +--echo # -- End of 5.0 tests +--echo # ------------------------------------------------------------------ ########################################################################### @@ -8056,4 +8135,6 @@ DROP FUNCTION f1; ########################################################################### ---echo End of 5.1 tests +--echo # ------------------------------------------------------------------ +--echo # -- End of 5.1 tests +--echo # ------------------------------------------------------------------ diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ad940f3f5ad..c86b0fefbdc 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3159,6 +3159,60 @@ select count(*) from t1 where f12 = drop table t1,t2; +# +# BUG#33794 "MySQL crashes executing specific query on specific dump" +# +CREATE TABLE t4 ( + f7 varchar(32) collate utf8_bin NOT NULL default '', + f10 varchar(32) collate utf8_bin default NULL, + PRIMARY KEY (f7) +); +INSERT INTO t4 VALUES(1,1), (2,null); + +CREATE TABLE t2 ( + f4 varchar(32) collate utf8_bin NOT NULL default '', + f2 varchar(50) collate utf8_bin default NULL, + f3 varchar(10) collate utf8_bin default NULL, + PRIMARY KEY (f4), + UNIQUE KEY uk1 (f2) +); +INSERT INTO t2 VALUES(1,1,null), (2,2,null); + +CREATE TABLE t1 ( + f8 varchar(32) collate utf8_bin NOT NULL default '', + f1 varchar(10) collate utf8_bin default NULL, + f9 varchar(32) collate utf8_bin default NULL, + PRIMARY KEY (f8) +); +INSERT INTO t1 VALUES (1,'P',1), (2,'P',1), (3,'R',2); + +CREATE TABLE t3 ( + f6 varchar(32) collate utf8_bin NOT NULL default '', + f5 varchar(50) collate utf8_bin default NULL, + PRIMARY KEY (f6) +); +INSERT INTO t3 VALUES (1,null), (2,null); + +SELECT + IF(t1.f1 = 'R', a1.f2, t2.f2) AS a4, + IF(t1.f1 = 'R', a1.f3, t2.f3) AS f3, + SUM( + IF( + (SELECT VPC.f2 + FROM t2 VPC, t4 a2, t2 a3 + WHERE + VPC.f4 = a2.f10 AND a3.f2 = a4 + LIMIT 1) IS NULL, + 0, + t3.f5 + ) + ) AS a6 +FROM + t2, t3, t1 JOIN t2 a1 ON t1.f9 = a1.f4 +GROUP BY a4; + +DROP TABLE t1, t2, t3, t4; + --echo End of 5.0 tests. # @@ -3194,3 +3248,4 @@ CREATE TABLE t1 (s1 char(1)); INSERT INTO t1 VALUES ('a'); SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1); DROP TABLE t1; + diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 807d1e6b01e..6841b3cdd68 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -478,4 +478,47 @@ select round(a,b) as c from t1 order by c; DROP TABLE t1, t2, t3, t4; +# +# Bug #33143: Incorrect ORDER BY for ROUND()/TRUNCATE() result +# + +CREATE TABLE t1( a DECIMAL(4, 3), b INT ); +INSERT INTO t1 VALUES ( 1, 5 ), ( 2, 4 ), ( 3, 3 ), ( 4, 2 ), ( 5, 1 ); +SELECT a, b, ROUND( a, b ) AS c FROM t1 ORDER BY c; +SELECT a, b, ROUND( a, b ) AS c FROM t1 ORDER BY c DESC; + +CREATE TABLE t2 ( a INT, b INT, c DECIMAL(5, 4) ); + +INSERT INTO t2 VALUES ( 0, 1, 1.2345 ), ( 1, 2, 1.2345 ), + ( 3, 3, 1.2345 ), ( 2, 4, 1.2345 ); + +SELECT a, b, MAX(ROUND(c, a)) +FROM t2 +GROUP BY a, b +ORDER BY b; + +SELECT a, b, ROUND(c, a) +FROM t2; + +CREATE TABLE t3( a INT, b DECIMAL(6, 3) ); +INSERT INTO t3 VALUES( 0, 1.5 ); +SELECT ROUND( b, a ) FROM t3; + +CREATE TABLE t4( a INT, b DECIMAL( 12, 0) ); +INSERT INTO t4 VALUES( -9, 1.5e9 ); +SELECT ROUND( b, a ) FROM t4; + +CREATE TABLE t5( a INT, b DECIMAL( 13, 12 ) ); +INSERT INTO t5 VALUES( 0, 1.5 ); +INSERT INTO t5 VALUES( 9, 1.5e-9 ); +SELECT ROUND( b, a ) FROM t5; + +CREATE TABLE t6( a INT ); +INSERT INTO t6 VALUES( 6 / 8 ); +SELECT * FROM t6; + +SELECT ROUND(20061108085411.000002); + +DROP TABLE t1, t2, t3, t4, t5, t6; + --echo End of 5.0 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 7f769c50449..58ef9c1eff1 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -3453,6 +3453,20 @@ DROP VIEW v2; DROP VIEW v3; DROP TABLE t1; +--echo # +--echo # Bug#29477: Not all fields of the target table were checked to have +--echo # a default value when inserting into a view. +--echo # +create table t1(f1 int, f2 int not null); +create view v1 as select f1 from t1; +insert into v1 values(1); +set @old_mode=@@sql_mode; +set @@sql_mode=traditional; +--error ER_NO_DEFAULT_FOR_VIEW_FIELD +insert into v1 values(1); +set @@sql_mode=@old_mode; +drop view v1; +drop table t1; --echo End of 5.0 tests. diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test index b5bae109f5f..d0eaaf1a764 100644 --- a/mysql-test/t/warnings.test +++ b/mysql-test/t/warnings.test @@ -65,6 +65,7 @@ create table t1(a tinyint NOT NULL, b tinyint unsigned, c char(5)); insert into t1 values(NULL,100,'mysql'),(10,-1,'mysql ab'),(500,256,'open source'),(20,NULL,'test'); alter table t1 modify c char(4); alter table t1 add d char(2); +--error 1048 update t1 set a=NULL where a=10; update t1 set c='mysql ab' where c='test'; update t1 set d=c; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 3f1634a6ad1..51070a525c5 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -367,7 +367,7 @@ bool ha_partition::initialise_partition(MEM_ROOT *mem_root) HA_CAN_GEOMETRY, HA_CAN_FULLTEXT, HA_CAN_SQL_HANDLER, HA_DUPLICATE_POS, HA_CAN_INSERT_DELAYED is disabled until further investigated. */ - m_table_flags= (ulong)m_file[0]->table_flags(); + m_table_flags= (ulong)m_file[0]->ha_table_flags(); m_low_byte_first= m_file[0]->low_byte_first(); m_pkey_is_clustered= TRUE; file_array= m_file; @@ -382,7 +382,7 @@ bool ha_partition::initialise_partition(MEM_ROOT *mem_root) } if (!file->primary_key_is_clustered()) m_pkey_is_clustered= FALSE; - m_table_flags&= file->table_flags(); + m_table_flags&= file->ha_table_flags(); } while (*(++file_array)); m_table_flags&= ~(HA_CAN_GEOMETRY | HA_CAN_FULLTEXT | HA_DUPLICATE_POS | HA_CAN_SQL_HANDLER | HA_CAN_INSERT_DELAYED | @@ -616,7 +616,7 @@ int ha_partition::drop_partitions(const char *path) sub_elem->partition_name, name_variant); file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - if ((ret_error= file->delete_table((const char *) part_name_buff))) + if ((ret_error= file->ha_delete_table(part_name_buff))) error= ret_error; if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -629,7 +629,7 @@ int ha_partition::drop_partitions(const char *path) TRUE); file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - if ((ret_error= file->delete_table((const char *) part_name_buff))) + if ((ret_error= file->ha_delete_table(part_name_buff))) error= ret_error; if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; @@ -707,7 +707,7 @@ int ha_partition::rename_partitions(const char *path) sub_elem->partition_name, NORMAL_PART_NAME); DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if ((ret_error= file->delete_table((const char *) norm_name_buff))) + if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -722,7 +722,7 @@ int ha_partition::rename_partitions(const char *path) part_elem->partition_name, NORMAL_PART_NAME, TRUE); DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if ((ret_error= file->delete_table((const char *) norm_name_buff))) + if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; @@ -778,7 +778,7 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); - if ((ret_error= file->delete_table((const char *) norm_name_buff))) + if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -791,8 +791,8 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff))) + if ((ret_error= file->ha_rename_table(part_name_buff, + norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; @@ -809,7 +809,7 @@ int ha_partition::rename_partitions(const char *path) { file= m_reorged_file[part_count++]; DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); - if ((ret_error= file->delete_table((const char *) norm_name_buff))) + if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; @@ -821,8 +821,8 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - if ((ret_error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff))) + if ((ret_error= file->ha_rename_table(part_name_buff, + norm_name_buff))) error= ret_error; else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) error= 1; @@ -1036,9 +1036,9 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, DBUG_PRINT("enter", ("flag = %u", flag)); if (flag == OPTIMIZE_PARTS) - error= file->optimize(thd, check_opt); + error= file->ha_optimize(thd, check_opt); else if (flag == ANALYZE_PARTS) - error= file->analyze(thd, check_opt); + error= file->ha_analyze(thd, check_opt); else if (flag == CHECK_PARTS) error= file->ha_check(thd, check_opt); else if (flag == REPAIR_PARTS) @@ -1139,7 +1139,7 @@ int ha_partition::prepare_new_partition(TABLE *tbl, if ((error= set_up_table_before_create(tbl, part_name, create_info, 0, p_elem))) goto error; - if ((error= file->create(part_name, tbl, create_info))) + if ((error= file->ha_create(part_name, tbl, create_info))) goto error; create_flag= TRUE; if ((error= file->ha_open(tbl, part_name, m_mode, m_open_test_lock))) @@ -1150,13 +1150,13 @@ int ha_partition::prepare_new_partition(TABLE *tbl, assumes that external_lock() is last call that may fail here. Otherwise see description for cleanup_new_partition(). */ - if ((error= file->external_lock(current_thd, m_lock_type))) + if ((error= file->ha_external_lock(current_thd, m_lock_type))) goto error; DBUG_RETURN(0); error: if (create_flag) - VOID(file->delete_table(part_name)); + VOID(file->ha_delete_table(part_name)); DBUG_RETURN(error); } @@ -1574,14 +1574,18 @@ int ha_partition::copy_partitions(ulonglong *copied, ulonglong *deleted) } else { + THD *thd= ha_thd(); /* Copy record to new handler */ copied++; - if ((result= m_new_file[new_part]->write_row(m_rec0))) + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + result= m_new_file[new_part]->ha_write_row(m_rec0); + reenable_binlog(thd); + if (result) goto error; } } late_extra_no_cache(reorg_part); - file->rnd_end(); + file->ha_rnd_end(); reorg_part++; } DBUG_RETURN(FALSE); @@ -1698,16 +1702,15 @@ uint ha_partition::del_ren_cre_table(const char *from, { // Rename branch create_partition_name(to_buff, to, name_buffer_ptr, NORMAL_PART_NAME, FALSE); - error= (*file)->rename_table((const char*) from_buff, - (const char*) to_buff); + error= (*file)->ha_rename_table(from_buff, to_buff); } else if (table_arg == NULL) // delete branch - error= (*file)->delete_table((const char*) from_buff); + error= (*file)->ha_delete_table(from_buff); else { if ((error= set_up_table_before_create(table_arg, from_buff, create_info, i, NULL)) || - ((error= (*file)->create(from_buff, table_arg, create_info)))) + ((error= (*file)->ha_create(from_buff, table_arg, create_info)))) goto create_error; } name_buffer_ptr= strend(name_buffer_ptr) + 1; @@ -1722,7 +1725,7 @@ create_error: { create_partition_name(from_buff, from, name_buffer_ptr, NORMAL_PART_NAME, FALSE); - VOID((*file)->delete_table((const char*) from_buff)); + VOID((*file)->ha_delete_table((const char*) from_buff)); name_buffer_ptr= strend(name_buffer_ptr) + 1; } DBUG_RETURN(error); @@ -2314,7 +2317,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) } /* Recalculate table flags as they may change after open */ - m_table_flags= m_file[0]->table_flags(); + m_table_flags= m_file[0]->ha_table_flags(); file= m_file; do { @@ -2326,7 +2329,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) m_no_locks+= (*file)->lock_count(); name_buffer_ptr+= strlen(name_buffer_ptr) + 1; set_if_bigger(ref_length, ((*file)->ref_length)); - m_table_flags&= (*file)->table_flags(); + m_table_flags&= (*file)->ha_table_flags(); } while (*(++file)); m_table_flags&= ~(HA_CAN_GEOMETRY | HA_CAN_FULLTEXT | HA_DUPLICATE_POS | HA_CAN_SQL_HANDLER | HA_CAN_INSERT_DELAYED); @@ -2482,7 +2485,7 @@ repeat: { DBUG_PRINT("info", ("external_lock(thd, %d) iteration %d", lock_type, (int) (file - m_file))); - if ((error= (*file)->external_lock(thd, lock_type))) + if ((error= (*file)->ha_external_lock(thd, lock_type))) { if (F_UNLCK != lock_type) goto err_handler; @@ -2501,7 +2504,7 @@ repeat: err_handler: while (file-- != m_file) { - (*file)->external_lock(thd, F_UNLCK); + (*file)->ha_external_lock(thd, F_UNLCK); } DBUG_RETURN(error); } @@ -2694,6 +2697,7 @@ int ha_partition::write_row(uchar * buf) longlong func_value; bool autoincrement_lock= FALSE; my_bitmap_map *old_map; + THD *thd= ha_thd(); #ifdef NOT_NEEDED uchar *rec0= m_rec0; #endif @@ -2765,7 +2769,9 @@ int ha_partition::write_row(uchar * buf) } m_last_part= part_id; DBUG_PRINT("info", ("Insert in partition %d", part_id)); - error= m_file[part_id]->write_row(buf); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= m_file[part_id]->ha_write_row(buf); + reenable_binlog(thd); exit: if (autoincrement_lock) pthread_mutex_unlock(&table_share->mutex); @@ -2806,6 +2812,7 @@ exit: int ha_partition::update_row(const uchar *old_data, uchar *new_data) { + THD *thd= ha_thd(); uint32 new_part_id, old_part_id; int error= 0; longlong func_value; @@ -2840,16 +2847,25 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) if (new_part_id == old_part_id) { DBUG_PRINT("info", ("Update in partition %d", new_part_id)); - error= m_file[new_part_id]->update_row(old_data, new_data); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= m_file[new_part_id]->ha_update_row(old_data, new_data); + reenable_binlog(thd); goto exit; } else { DBUG_PRINT("info", ("Update from partition %d to partition %d", old_part_id, new_part_id)); - if ((error= m_file[new_part_id]->write_row(new_data))) + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= m_file[new_part_id]->ha_write_row(new_data); + reenable_binlog(thd); + if (error) goto exit; - if ((error= m_file[old_part_id]->delete_row(old_data))) + + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ + error= m_file[old_part_id]->ha_delete_row(old_data); + reenable_binlog(thd); + if (error) { #ifdef IN_THE_FUTURE (void) m_file[new_part_id]->delete_last_inserted_row(new_data); @@ -2896,6 +2912,7 @@ int ha_partition::delete_row(const uchar *buf) { uint32 part_id; int error; + THD *thd= ha_thd(); DBUG_ENTER("ha_partition::delete_row"); if ((error= get_part_for_delete(buf, m_rec0, m_part_info, &part_id))) @@ -2903,7 +2920,10 @@ int ha_partition::delete_row(const uchar *buf) DBUG_RETURN(error); } m_last_part= part_id; - DBUG_RETURN(m_file[part_id]->delete_row(buf)); + tmp_disable_binlog(thd); + error= m_file[part_id]->ha_delete_row(buf); + reenable_binlog(thd); + DBUG_RETURN(error); } @@ -2938,7 +2958,7 @@ int ha_partition::delete_all_rows() file= m_file; do { - if ((error= (*file)->delete_all_rows())) + if ((error= (*file)->ha_delete_all_rows())) DBUG_RETURN(error); } while (*(++file)); DBUG_RETURN(0); @@ -3980,7 +4000,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag) int ha_partition::handle_unordered_next(uchar *buf, bool is_next_same) { - handler *file= file= m_file[m_part_spec.start_part]; + handler *file= m_file[m_part_spec.start_part]; int error; DBUG_ENTER("ha_partition::handle_unordered_next"); @@ -3999,7 +4019,7 @@ int ha_partition::handle_unordered_next(uchar *buf, bool is_next_same) } else if (!(error= file->index_next(buf))) { - if (!(file->table_flags() & HA_READ_ORDER) || + if (!(file->ha_table_flags() & HA_READ_ORDER) || compare_key(end_range) <= 0) { m_last_part= m_part_spec.start_part; @@ -4077,7 +4097,7 @@ int ha_partition::handle_unordered_scan_next_partition(uchar * buf) } if (!error) { - if (!(file->table_flags() & HA_READ_ORDER) || + if (!(file->ha_table_flags() & HA_READ_ORDER) || compare_key(end_range) <= 0) { m_last_part= i; @@ -4999,7 +5019,7 @@ int ha_partition::reset(void) file= m_file; do { - if ((tmp= (*file)->reset())) + if ((tmp= (*file)->ha_reset())) result= tmp; } while (*(++file)); DBUG_RETURN(result); @@ -5641,7 +5661,7 @@ void ha_partition::release_auto_increment() for (uint i= 0; i < m_tot_parts; i++) { - m_file[i]->release_auto_increment(); + m_file[i]->ha_release_auto_increment(); } DBUG_VOID_RETURN; } @@ -5677,7 +5697,7 @@ int ha_partition::disable_indexes(uint mode) for (file= m_file; *file; file++) { - if ((error= (*file)->disable_indexes(mode))) + if ((error= (*file)->ha_disable_indexes(mode))) break; } return error; @@ -5701,7 +5721,7 @@ int ha_partition::enable_indexes(uint mode) for (file= m_file; *file; file++) { - if ((error= (*file)->enable_indexes(mode))) + if ((error= (*file)->ha_enable_indexes(mode))) break; } return error; diff --git a/sql/handler.cc b/sql/handler.cc index 0715ef3cc9c..95d63740039 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1479,7 +1479,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, DBUG_RETURN(ENOENT); path= check_lowercase_names(file, path, tmp_path); - if ((error= file->delete_table(path)) && generate_warning) + if ((error= file->ha_delete_table(path)) && generate_warning) { /* Because file->print_error() use my_error() to generate the error message @@ -1498,8 +1498,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, dummy_share.table_name.length= strlen(alias); dummy_table.alias= alias; - file->table_share= &dummy_share; - file->table= &dummy_table; + file->change_table_ptr(&dummy_table, &dummy_share); thd->push_internal_handler(&ha_delete_table_error_handler); file->print_error(error, 0); @@ -2508,6 +2507,12 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) } +/** + Repair table: public interface. + + @sa handler::repair() +*/ + int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) { int result; @@ -2518,6 +2523,328 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) /** + Bulk update row: public interface. + + @sa handler::bulk_update_row() +*/ + +int +handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, + uint *dup_key_found) +{ + return bulk_update_row(old_data, new_data, dup_key_found); +} + + +/** + Delete all rows: public interface. + + @sa handler::delete_all_rows() +*/ + +int +handler::ha_delete_all_rows() +{ + return delete_all_rows(); +} + + +/** + Reset auto increment: public interface. + + @sa handler::reset_auto_increment() +*/ + +int +handler::ha_reset_auto_increment(ulonglong value) +{ + return reset_auto_increment(value); +} + + +/** + Backup table: public interface. + + @sa handler::backup() +*/ + +int +handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt) +{ + return backup(thd, check_opt); +} + + +/** + Restore table: public interface. + + @sa handler::restore() +*/ + +int +handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt) +{ + return restore(thd, check_opt); +} + + +/** + Optimize table: public interface. + + @sa handler::optimize() +*/ + +int +handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt) +{ + return optimize(thd, check_opt); +} + + +/** + Analyze table: public interface. + + @sa handler::analyze() +*/ + +int +handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt) +{ + return analyze(thd, check_opt); +} + + +/** + Check and repair table: public interface. + + @sa handler::check_and_repair() +*/ + +bool +handler::ha_check_and_repair(THD *thd) +{ + return check_and_repair(thd); +} + + +/** + Disable indexes: public interface. + + @sa handler::disable_indexes() +*/ + +int +handler::ha_disable_indexes(uint mode) +{ + return disable_indexes(mode); +} + + +/** + Enable indexes: public interface. + + @sa handler::enable_indexes() +*/ + +int +handler::ha_enable_indexes(uint mode) +{ + return enable_indexes(mode); +} + + +/** + Discard or import tablespace: public interface. + + @sa handler::discard_or_import_tablespace() +*/ + +int +handler::ha_discard_or_import_tablespace(my_bool discard) +{ + return discard_or_import_tablespace(discard); +} + + +/** + Prepare for alter: public interface. + + Called to prepare an *online* ALTER. + + @sa handler::prepare_for_alter() +*/ + +void +handler::ha_prepare_for_alter() +{ + prepare_for_alter(); +} + + +/** + Rename table: public interface. + + @sa handler::rename_table() +*/ + +int +handler::ha_rename_table(const char *from, const char *to) +{ + return rename_table(from, to); +} + + +/** + Delete table: public interface. + + @sa handler::delete_table() +*/ + +int +handler::ha_delete_table(const char *name) +{ + return delete_table(name); +} + + +/** + Drop table in the engine: public interface. + + @sa handler::drop_table() +*/ + +void +handler::ha_drop_table(const char *name) +{ + return drop_table(name); +} + + +/** + Create a table in the engine: public interface. + + @sa handler::create() +*/ + +int +handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info) +{ + return create(name, form, info); +} + + +/** + Create handler files for CREATE TABLE: public interface. + + @sa handler::create_handler_files() +*/ + +int +handler::ha_create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info) +{ + return create_handler_files(name, old_name, action_flag, info); +} + + +/** + Change partitions: public interface. + + @sa handler::change_partitions() +*/ + +int +handler::ha_change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong *copied, + ulonglong *deleted, + const uchar *pack_frm_data, + size_t pack_frm_len) +{ + return change_partitions(create_info, path, copied, deleted, + pack_frm_data, pack_frm_len); +} + + +/** + Drop partitions: public interface. + + @sa handler::drop_partitions() +*/ + +int +handler::ha_drop_partitions(const char *path) +{ + return drop_partitions(path); +} + + +/** + Rename partitions: public interface. + + @sa handler::rename_partitions() +*/ + +int +handler::ha_rename_partitions(const char *path) +{ + return rename_partitions(path); +} + + +/** + Optimize partitions: public interface. + + @sa handler::optimize_partitions() +*/ + +int +handler::ha_optimize_partitions(THD *thd) +{ + return optimize_partitions(thd); +} + + +/** + Analyze partitions: public interface. + + @sa handler::analyze_partitions() +*/ + +int +handler::ha_analyze_partitions(THD *thd) +{ + return analyze_partitions(thd); +} + + +/** + Check partitions: public interface. + + @sa handler::check_partitions() +*/ + +int +handler::ha_check_partitions(THD *thd) +{ + return check_partitions(thd); +} + + +/** + Repair partitions: public interface. + + @sa handler::repair_partitions() +*/ + +int +handler::ha_repair_partitions(THD *thd) +{ + return repair_partitions(thd); +} + + +/** Tell the storage engine that it is allowed to "disable transaction" in the handler. It is a hint that ACID is not required - it is used in NDB for ALTER TABLE, for example, when data are copied to temporary table. @@ -2657,7 +2984,7 @@ int ha_create_table(THD *thd, const char *path, name= check_lowercase_names(table.file, share.path.str, name_buff); - error= table.file->create(name, &table, create_info); + error= table.file->ha_create(name, &table, create_info); VOID(closefrm(&table, 0)); if (error) { @@ -2728,7 +3055,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE; check_lowercase_names(table.file, path, path); - error=table.file->create(path,&table,&create_info); + error=table.file->ha_create(path, &table, &create_info); VOID(closefrm(&table, 1)); DBUG_RETURN(error != 0); diff --git a/sql/handler.h b/sql/handler.h index c5b867e315f..b3a4b408589 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -967,10 +967,6 @@ uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map); class handler :public Sql_alloc { - friend class ha_partition; - friend int ha_delete_table(THD*,handlerton*,const char*,const char*, - const char*,bool); - public: typedef ulonglong Table_flags; protected: @@ -1118,6 +1114,40 @@ public: estimation_rows_to_insert= 0; return end_bulk_insert(); } + int ha_bulk_update_row(const uchar *old_data, uchar *new_data, + uint *dup_key_found); + int ha_delete_all_rows(); + int ha_reset_auto_increment(ulonglong value); + int ha_backup(THD* thd, HA_CHECK_OPT* check_opt); + int ha_restore(THD* thd, HA_CHECK_OPT* check_opt); + int ha_optimize(THD* thd, HA_CHECK_OPT* check_opt); + int ha_analyze(THD* thd, HA_CHECK_OPT* check_opt); + bool ha_check_and_repair(THD *thd); + int ha_disable_indexes(uint mode); + int ha_enable_indexes(uint mode); + int ha_discard_or_import_tablespace(my_bool discard); + void ha_prepare_for_alter(); + int ha_rename_table(const char *from, const char *to); + int ha_delete_table(const char *name); + void ha_drop_table(const char *name); + + int ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info); + + int ha_create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info); + + int ha_change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong *copied, + ulonglong *deleted, + const uchar *pack_frm_data, + size_t pack_frm_len); + int ha_drop_partitions(const char *path); + int ha_rename_partitions(const char *path); + int ha_optimize_partitions(THD *thd); + int ha_analyze_partitions(THD *thd); + int ha_check_partitions(THD *thd); + int ha_repair_partitions(THD *thd); void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); @@ -1204,25 +1234,6 @@ public: */ virtual bool start_bulk_delete() { return 1; } /** - This method is similar to update_row, however the handler doesn't need - to execute the updates at this point in time. The handler can be certain - that another call to bulk_update_row will occur OR a call to - exec_bulk_update before the set of updates in this query is concluded. - - @param old_data Old record - @param new_data New record - @param dup_key_found Number of duplicate keys found - - @retval 0 Bulk delete used by handler - @retval 1 Bulk delete not used, normal operation used - */ - virtual int bulk_update_row(const uchar *old_data, uchar *new_data, - uint *dup_key_found) - { - DBUG_ASSERT(FALSE); - return HA_ERR_WRONG_COMMAND; - } - /** After this call all outstanding updates must be performed. The number of duplicate key errors are reported in the duplicate key parameter. It is allowed to continue to the batched update after this call, the @@ -1365,14 +1376,6 @@ public: virtual void try_semi_consistent_read(bool) {} virtual void unlock_row() {} virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} - /** - This is called to delete all rows in a table - If the handler don't support this, then this function will - return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one - by one. - */ - virtual int delete_all_rows() - { return (my_errno=HA_ERR_WRONG_COMMAND); } virtual void get_auto_increment(ulonglong offset, ulonglong increment, ulonglong nb_desired_values, ulonglong *first_value, @@ -1397,42 +1400,17 @@ public: next_insert_id= (prev_insert_id > 0) ? prev_insert_id : insert_id_for_cur_row; } - /** - Reset the auto-increment counter to the given value, i.e. the next row - inserted will get the given value. This is called e.g. after TRUNCATE - is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is - returned by storage engines that don't support this operation. - */ - virtual int reset_auto_increment(ulonglong value) - { return HA_ERR_WRONG_COMMAND; } virtual void update_create_info(HA_CREATE_INFO *create_info) {} int check_old_types(); - virtual int backup(THD* thd, HA_CHECK_OPT* check_opt) - { return HA_ADMIN_NOT_IMPLEMENTED; } - /** - Restore assumes .frm file must exist, and that generate_table() has been - called; It will just copy the data file and run repair. - */ - virtual int restore(THD* thd, HA_CHECK_OPT* check_opt) - { return HA_ADMIN_NOT_IMPLEMENTED; } - virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt) - { return HA_ADMIN_NOT_IMPLEMENTED; } - virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt) - { return HA_ADMIN_NOT_IMPLEMENTED; } virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } /* end of the list of admin commands */ - virtual bool check_and_repair(THD *thd) { return HA_ERR_WRONG_COMMAND; } virtual int dump(THD* thd, int fd = -1) { return HA_ERR_WRONG_COMMAND; } - virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } - virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } virtual int indexes_are_disabled(void) {return 0;} - virtual int discard_or_import_tablespace(my_bool discard) - {return HA_ERR_WRONG_COMMAND;} virtual int net_read_dump(NET* net) { return HA_ERR_WRONG_COMMAND; } virtual char *update_table_comment(const char * comment) { return (char*) comment;} @@ -1489,7 +1467,6 @@ public: virtual ulong index_flags(uint idx, uint part, bool all_parts) const =0; - virtual void prepare_for_alter() { return; } virtual int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys) { return (HA_ERR_WRONG_COMMAND); } virtual int prepare_drop_index(TABLE *table_arg, uint *key_num, @@ -1521,44 +1498,12 @@ public: virtual bool is_crashed() const { return 0; } virtual bool auto_repair() const { return 0; } - /** - default rename_table() and delete_table() rename/delete files with a - given name and extensions from bas_ext() - */ - virtual int rename_table(const char *from, const char *to); - virtual int delete_table(const char *name); - virtual void drop_table(const char *name); - - virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; #define CHF_CREATE_FLAG 0 #define CHF_DELETE_FLAG 1 #define CHF_RENAME_FLAG 2 #define CHF_INDEX_FLAG 3 - virtual int create_handler_files(const char *name, const char *old_name, - int action_flag, HA_CREATE_INFO *info) - { return FALSE; } - - virtual int change_partitions(HA_CREATE_INFO *create_info, - const char *path, - ulonglong *copied, - ulonglong *deleted, - const uchar *pack_frm_data, - size_t pack_frm_len) - { return HA_ERR_WRONG_COMMAND; } - virtual int drop_partitions(const char *path) - { return HA_ERR_WRONG_COMMAND; } - virtual int rename_partitions(const char *path) - { return HA_ERR_WRONG_COMMAND; } - virtual int optimize_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int analyze_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int check_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int repair_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } /** @note lock_count() can return > 1 if the table is MERGE or partitioned. @@ -1674,22 +1619,6 @@ public: uint table_changes) { return COMPATIBLE_DATA_NO; } - /** These are only called from sql_select for internal temporary tables */ - virtual int write_row(uchar *buf __attribute__((unused))) - { - return HA_ERR_WRONG_COMMAND; - } - - virtual int update_row(const uchar *old_data __attribute__((unused)), - uchar *new_data __attribute__((unused))) - { - return HA_ERR_WRONG_COMMAND; - } - - virtual int delete_row(const uchar *buf __attribute__((unused))) - { - return HA_ERR_WRONG_COMMAND; - } /** use_hidden_primary_key() is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined @@ -1702,6 +1631,16 @@ protected: void ha_statistic_increment(ulong SSV::*offset) const; void **ha_data(THD *) const; THD *ha_thd(void) const; + + /** + Default rename_table() and delete_table() rename/delete files with a + given name and extensions from bas_ext(). + + These methods can be overridden, but their default implementation + provide useful functionality. + */ + virtual int rename_table(const char *from, const char *to); + virtual int delete_table(const char *name); private: /* Low-level primitives for storage engines. These should be @@ -1721,6 +1660,21 @@ private: */ virtual int rnd_init(bool scan)= 0; virtual int rnd_end() { return 0; } + virtual int write_row(uchar *buf __attribute__((unused))) + { + return HA_ERR_WRONG_COMMAND; + } + + virtual int update_row(const uchar *old_data __attribute__((unused)), + uchar *new_data __attribute__((unused))) + { + return HA_ERR_WRONG_COMMAND; + } + + virtual int delete_row(const uchar *buf __attribute__((unused))) + { + return HA_ERR_WRONG_COMMAND; + } /** Reset state of file to after 'open'. This function is called after every statement for all tables used @@ -1776,6 +1730,85 @@ private: { return HA_ERR_WRONG_COMMAND; } virtual int index_read_last(uchar * buf, const uchar * key, uint key_len) { return (my_errno= HA_ERR_WRONG_COMMAND); } + /** + This method is similar to update_row, however the handler doesn't need + to execute the updates at this point in time. The handler can be certain + that another call to bulk_update_row will occur OR a call to + exec_bulk_update before the set of updates in this query is concluded. + + @param old_data Old record + @param new_data New record + @param dup_key_found Number of duplicate keys found + + @retval 0 Bulk delete used by handler + @retval 1 Bulk delete not used, normal operation used + */ + virtual int bulk_update_row(const uchar *old_data, uchar *new_data, + uint *dup_key_found) + { + DBUG_ASSERT(FALSE); + return HA_ERR_WRONG_COMMAND; + } + /** + This is called to delete all rows in a table + If the handler don't support this, then this function will + return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one + by one. + */ + virtual int delete_all_rows() + { return (my_errno=HA_ERR_WRONG_COMMAND); } + /** + Reset the auto-increment counter to the given value, i.e. the next row + inserted will get the given value. This is called e.g. after TRUNCATE + is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is + returned by storage engines that don't support this operation. + */ + virtual int reset_auto_increment(ulonglong value) + { return HA_ERR_WRONG_COMMAND; } + virtual int backup(THD* thd, HA_CHECK_OPT* check_opt) + { return HA_ADMIN_NOT_IMPLEMENTED; } + /** + Restore assumes .frm file must exist, and that generate_table() has been + called; It will just copy the data file and run repair. + */ + virtual int restore(THD* thd, HA_CHECK_OPT* check_opt) + { return HA_ADMIN_NOT_IMPLEMENTED; } + virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt) + { return HA_ADMIN_NOT_IMPLEMENTED; } + virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt) + { return HA_ADMIN_NOT_IMPLEMENTED; } + virtual bool check_and_repair(THD *thd) { return HA_ERR_WRONG_COMMAND; } + virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } + virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } + virtual int discard_or_import_tablespace(my_bool discard) + { return (my_errno=HA_ERR_WRONG_COMMAND); } + virtual void prepare_for_alter() { return; } + virtual void drop_table(const char *name); + virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; + + virtual int create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info) + { return FALSE; } + + virtual int change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong *copied, + ulonglong *deleted, + const uchar *pack_frm_data, + size_t pack_frm_len) + { return HA_ERR_WRONG_COMMAND; } + virtual int drop_partitions(const char *path) + { return HA_ERR_WRONG_COMMAND; } + virtual int rename_partitions(const char *path) + { return HA_ERR_WRONG_COMMAND; } + virtual int optimize_partitions(THD *thd) + { return HA_ERR_WRONG_COMMAND; } + virtual int analyze_partitions(THD *thd) + { return HA_ERR_WRONG_COMMAND; } + virtual int check_partitions(THD *thd) + { return HA_ERR_WRONG_COMMAND; } + virtual int repair_partitions(THD *thd) + { return HA_ERR_WRONG_COMMAND; } }; diff --git a/sql/item.cc b/sql/item.cc index 463de3e1c52..c546badd8e7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3418,7 +3418,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) @param thd current thread @param ref column reference being resolved - @param select the sub-select that ref is resolved against + @param select the select that ref is resolved against @note The resolution procedure is: @@ -3478,6 +3478,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) } if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && + select->having_fix_field && select_ref != not_found_item && !group_by_ref) { /* diff --git a/sql/item_func.cc b/sql/item_func.cc index be8966598d6..6e9371de9dc 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1994,7 +1994,7 @@ void Item_func_round::fix_length_and_dec() int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; precision-= decimals_delta - length_increase; - decimals= decimals_to_set; + decimals= min(decimals_to_set, DECIMAL_MAX_SCALE); max_length= my_decimal_precision_to_length(precision, decimals, unsigned_flag); break; @@ -2093,18 +2093,18 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) { my_decimal val, *value= args[0]->val_decimal(&val); longlong dec= args[1]->val_int(); - if (dec > 0 || (dec < 0 && args[1]->unsigned_flag)) - { + if (dec >= 0 || args[1]->unsigned_flag) dec= min((ulonglong) dec, decimals); - decimals= (uint8) dec; // to get correct output - } else if (dec < INT_MIN) dec= INT_MIN; if (!(null_value= (args[0]->null_value || args[1]->null_value || my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec, - truncate, decimal_value) > 1))) + truncate, decimal_value) > 1))) + { + decimal_value->frac= decimals; return decimal_value; + } return 0; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 91198d0fb7e..27b964a9e15 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2617,7 +2617,7 @@ void Item_sum_count_distinct::clear() else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); - table->file->delete_all_rows(); + table->file->ha_delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); } } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2471ab3f81f..7b331d42941 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -608,7 +608,10 @@ char *opt_logname, *opt_slow_logname; /* Static variables */ static bool kill_in_progress, segfaulted; -static my_bool opt_do_pstack, opt_bootstrap, opt_myisam_log; +#ifdef HAVE_STACK_TRACE_ON_SEGV +static my_bool opt_do_pstack; +#endif /* HAVE_STACK_TRACE_ON_SEGV */ +static my_bool opt_bootstrap, opt_myisam_log; static int cleanup_done; static ulong opt_specialflag, opt_myisam_block_size; static char *opt_update_logname, *opt_binlog_index_name; @@ -5461,9 +5464,11 @@ struct my_option my_long_options[] = (uchar**) &opt_enable_named_pipe, (uchar**) &opt_enable_named_pipe, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif +#ifdef HAVE_STACK_TRACE_ON_SEGV {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.", (uchar**) &opt_do_pstack, (uchar**) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif /* HAVE_STACK_TRACE_ON_SEGV */ {"engine-condition-pushdown", OPT_ENGINE_CONDITION_PUSHDOWN, "Push supported query conditions to the storage engine.", diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 4a0e18129ad..0edb566ed9f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2120,11 +2120,17 @@ sp_head::backpatch(sp_label_t *lab) uint dest= instructions(); List_iterator_fast<bp_t> li(m_backpatch); + DBUG_ENTER("sp_head::backpatch"); while ((bp= li++)) { if (bp->lab == lab) + { + DBUG_PRINT("info", ("backpatch: (m_ip %d, label 0x%lx <%s>) to dest %d", + bp->instr->m_ip, (ulong) lab, lab->name, dest)); bp->instr->backpatch(dest, lab->ctx); + } } + DBUG_VOID_RETURN; } /** diff --git a/sql/sp_head.h b/sql/sp_head.h index 01a4cb73704..8d7062740c8 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -888,8 +888,9 @@ public: virtual void backpatch(uint dest, sp_pcontext *dst_ctx) { - if (m_dest == 0) // Don't reset - m_dest= dest; + /* Calling backpatch twice is a logic flaw in jump resolution. */ + DBUG_ASSERT(m_dest == 0); + m_dest= dest; } /** diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 8395648689b..9b237b3e7cc 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -314,17 +314,91 @@ sp_rcontext::handle_error(uint sql_errno, void sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) { + DBUG_ENTER("sp_rcontext::push_cursor"); + DBUG_ASSERT(m_ccount < m_root_parsing_ctx->max_cursor_index()); m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i); + DBUG_PRINT("info", ("m_ccount: %d", m_ccount)); + DBUG_VOID_RETURN; } - void sp_rcontext::pop_cursors(uint count) { + DBUG_ENTER("sp_rcontext::pop_cursors"); + DBUG_ASSERT(m_ccount >= count); while (count--) { delete m_cstack[--m_ccount]; } + DBUG_PRINT("info", ("m_ccount: %d", m_ccount)); + DBUG_VOID_RETURN; +} + +void +sp_rcontext::push_handler(struct sp_cond_type *cond, uint h, int type, uint f) +{ + DBUG_ENTER("sp_rcontext::push_handler"); + DBUG_ASSERT(m_hcount < m_root_parsing_ctx->max_handler_index()); + + m_handler[m_hcount].cond= cond; + m_handler[m_hcount].handler= h; + m_handler[m_hcount].type= type; + m_handler[m_hcount].foffset= f; + m_hcount+= 1; + + DBUG_PRINT("info", ("m_hcount: %d", m_hcount)); + DBUG_VOID_RETURN; +} + +void +sp_rcontext::pop_handlers(uint count) +{ + DBUG_ENTER("sp_rcontext::pop_handlers"); + DBUG_ASSERT(m_hcount >= count); + m_hcount-= count; + DBUG_PRINT("info", ("m_hcount: %d", m_hcount)); + DBUG_VOID_RETURN; +} + +void +sp_rcontext::push_hstack(uint h) +{ + DBUG_ENTER("sp_rcontext::push_hstack"); + DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index()); + m_hstack[m_hsp++]= h; + DBUG_PRINT("info", ("m_hsp: %d", m_hsp)); + DBUG_VOID_RETURN; +} + +uint +sp_rcontext::pop_hstack() +{ + uint handler; + DBUG_ENTER("sp_rcontext::pop_hstack"); + DBUG_ASSERT(m_hsp); + handler= m_hstack[--m_hsp]; + DBUG_PRINT("info", ("m_hsp: %d", m_hsp)); + DBUG_RETURN(handler); +} + +void +sp_rcontext::enter_handler(int hid) +{ + DBUG_ENTER("sp_rcontext::enter_handler"); + DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index()); + m_in_handler[m_ihsp++]= hid; + DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); + DBUG_VOID_RETURN; +} + +void +sp_rcontext::exit_handler() +{ + DBUG_ENTER("sp_rcontext::exit_handler"); + DBUG_ASSERT(m_ihsp); + m_ihsp-= 1; + DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); + DBUG_VOID_RETURN; } diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 43102cfeeb2..368a017da21 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -107,21 +107,9 @@ class sp_rcontext : public Sql_alloc return m_return_value_set; } - inline void - push_handler(struct sp_cond_type *cond, uint h, int type, uint f) - { - m_handler[m_hcount].cond= cond; - m_handler[m_hcount].handler= h; - m_handler[m_hcount].type= type; - m_handler[m_hcount].foffset= f; - m_hcount+= 1; - } + void push_handler(struct sp_cond_type *cond, uint h, int type, uint f); - inline void - pop_handlers(uint count) - { - m_hcount-= count; - } + void pop_handlers(uint count); // Returns 1 if a handler was found, 0 otherwise. bool @@ -158,29 +146,13 @@ class sp_rcontext : public Sql_alloc m_hfound= -1; } - inline void - push_hstack(uint h) - { - m_hstack[m_hsp++]= h; - } + void push_hstack(uint h); - inline uint - pop_hstack() - { - return m_hstack[--m_hsp]; - } + uint pop_hstack(); - inline void - enter_handler(int hid) - { - m_in_handler[m_ihsp++]= hid; - } + void enter_handler(int hid); - inline void - exit_handler() - { - m_ihsp-= 1; - } + void exit_handler(); void push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 41596b4faf2..799cb673a0e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3934,7 +3934,7 @@ retry: READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, ha_open_options | HA_OPEN_FOR_REPAIR, entry, FALSE) || ! entry->file || - (entry->file->is_crashed() && entry->file->check_and_repair(thd))) + (entry->file->is_crashed() && entry->file->ha_check_and_repair(thd))) { /* Give right error message */ thd->clear_error(); @@ -5400,7 +5400,7 @@ bool rm_temporary_table(handlerton *base, char *path) error=1; /* purecov: inspected */ *ext= 0; // remove extension file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base); - if (file && file->delete_table(path)) + if (file && file->ha_delete_table(path)) { error=1; sql_print_warning("Could not remove temporary table: '%s', error: %d", @@ -8099,7 +8099,7 @@ my_bool mysql_rm_tmp_tables(void) ((handler_file= get_new_handler(&share, thd->mem_root, share.db_type())))) { - handler_file->delete_table(filePathCopy); + handler_file->ha_delete_table(filePathCopy); delete handler_file; } free_table_share(&share); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index e51c53f644e..7e54f87fe14 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -371,6 +371,32 @@ TODO list: __LINE__,(ulong)(B)));B->query()->unlock_reading();} #define DUMP(C) DBUG_EXECUTE("qcache", {\ (C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();}) + + +/** + Causes the thread to wait in a spin lock for a query kill signal. + This function is used by the test frame work to identify race conditions. + + The signal is caught and ignored and the thread is not killed. +*/ + +static void debug_wait_for_kill(const char *info) +{ + DBUG_ENTER("debug_wait_for_kill"); + const char *prev_info; + THD *thd; + thd= current_thd; + prev_info= thd->proc_info; + thd->proc_info= info; + sql_print_information(info); + while(!thd->killed) + my_sleep(1000); + thd->killed= THD::NOT_KILLED; + sql_print_information("Exit debug_wait_for_kill"); + thd->proc_info= prev_info; + DBUG_VOID_RETURN; +} + #else #define MUTEX_LOCK(M) pthread_mutex_lock(M) #define MUTEX_UNLOCK(M) pthread_mutex_unlock(M) @@ -647,13 +673,16 @@ void query_cache_insert(NET *net, const char *packet, ulong length) if (net->query_cache_query == 0) DBUG_VOID_RETURN; + DBUG_EXECUTE_IF("wait_in_query_cache_insert", + debug_wait_for_kill("wait_in_query_cache_insert"); ); + STRUCT_LOCK(&query_cache.structure_guard_mutex); bool interrupt; query_cache.wait_while_table_flush_is_in_progress(&interrupt); if (interrupt) { STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - return; + DBUG_VOID_RETURN; } Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query; @@ -667,11 +696,11 @@ void query_cache_insert(NET *net, const char *packet, ulong length) DBUG_VOID_RETURN; } + BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); Query_cache_block *result= header->result(); DUMP(&query_cache); - BLOCK_LOCK_WR(query_block); DBUG_PRINT("qcache", ("insert packet %lu bytes long",length)); /* @@ -687,6 +716,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block)); // The following call will remove the lock on query_block query_cache.free_query(query_block); + query_cache.refused++; // append_result_data no success => we need unlock STRUCT_UNLOCK(&query_cache.structure_guard_mutex); DBUG_VOID_RETURN; @@ -886,6 +916,31 @@ ulong Query_cache::resize(ulong query_cache_size_arg) m_cache_status= Query_cache::FLUSH_IN_PROGRESS; STRUCT_UNLOCK(&structure_guard_mutex); + /* + Wait for all readers and writers to exit. When the list of all queries + is iterated over with a block level lock, we are done. + */ + Query_cache_block *block= queries_blocks; + if (block) + { + do + { + BLOCK_LOCK_WR(block); + Query_cache_query *query= block->query(); + if (query && query->writer()) + { + /* + Drop the writer; this will cancel any attempts to store + the processed statement associated with this writer. + */ + query->writer()->query_cache_query= 0; + query->writer(0); + refused++; + } + BLOCK_UNLOCK_WR(block); + block= block->next; + } while (block != queries_blocks); + } free_cache(); query_cache_size= query_cache_size_arg; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 56748772523..c6435387f44 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -123,7 +123,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); ha_rows const maybe_deleted= table->file->stats.records; DBUG_PRINT("debug", ("Trying to use delete_all_rows()")); - if (!(error=table->file->delete_all_rows())) + if (!(error=table->file->ha_delete_all_rows())) { error= -1; // ok deleted= maybe_deleted; @@ -328,7 +328,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, We're really doing a truncate and need to reset the table's auto-increment counter. */ - int error2= table->file->reset_auto_increment(0); + int error2= table->file->ha_reset_auto_increment(0); if (error2 && (error2 != HA_ERR_WRONG_COMMAND)) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f9dbd402de7..c2b1990f6c7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -619,7 +619,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (mysql_prepare_insert(thd, table_list, table, fields, values, update_fields, update_values, duplic, &unused_conds, FALSE, - (fields.elements || !value_count), + (fields.elements || !value_count || + table_list->view != 0), !ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))) @@ -1862,7 +1863,6 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) { if (!(di= new Delayed_insert())) { - my_error(ER_OUTOFMEMORY,MYF(0),sizeof(Delayed_insert)); thd->fatal_error(); goto end_create; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ce70e177a85..eabf4526f7b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5108,9 +5108,9 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); - if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, - &lpt->deleted, lpt->pack_frm_data, - lpt->pack_frm_len))) + if ((error= file->ha_change_partitions(lpt->create_info, path, &lpt->copied, + &lpt->deleted, lpt->pack_frm_data, + lpt->pack_frm_len))) { if (error != ER_OUTOFMEMORY) file->print_error(error, MYF(0)); @@ -5148,7 +5148,7 @@ static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("mysql_rename_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); - if ((error= lpt->table->file->rename_partitions(path))) + if ((error= lpt->table->file->ha_rename_partitions(path))) { if (error != 1) lpt->table->file->print_error(error, MYF(0)); @@ -5189,7 +5189,7 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("mysql_drop_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); - if ((error= lpt->table->file->drop_partitions(path))) + if ((error= lpt->table->file->ha_drop_partitions(path))) { lpt->table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); @@ -6105,13 +6105,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, int error; written_bin_log= FALSE; if (((alter_info->flags & ALTER_OPTIMIZE_PARTITION) && - (error= table->file->optimize_partitions(thd))) || + (error= table->file->ha_optimize_partitions(thd))) || ((alter_info->flags & ALTER_ANALYZE_PARTITION) && - (error= table->file->analyze_partitions(thd))) || + (error= table->file->ha_analyze_partitions(thd))) || ((alter_info->flags & ALTER_CHECK_PARTITION) && - (error= table->file->check_partitions(thd))) || + (error= table->file->ha_check_partitions(thd))) || ((alter_info->flags & ALTER_REPAIR_PARTITION) && - (error= table->file->repair_partitions(thd)))) + (error= table->file->ha_repair_partitions(thd)))) { table->file->print_error(error, MYF(0)); goto err; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d77fa6bbb04..d7e7be87d23 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1567,14 +1567,14 @@ JOIN::reinit() if (exec_tmp_table1) { exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE); - exec_tmp_table1->file->delete_all_rows(); + exec_tmp_table1->file->ha_delete_all_rows(); free_io_cache(exec_tmp_table1); filesort_free_buffers(exec_tmp_table1,0); } if (exec_tmp_table2) { exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE); - exec_tmp_table2->file->delete_all_rows(); + exec_tmp_table2->file->ha_delete_all_rows(); free_io_cache(exec_tmp_table2); filesort_free_buffers(exec_tmp_table2,0); } @@ -5618,7 +5618,8 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables, (keyuse->val->type() == Item::REF_ITEM && ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF && (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() == - Item_ref::DIRECT_REF) ) + Item_ref::DIRECT_REF && + keyuse->val->real_item()->type() == Item::FIELD_ITEM)) return new store_key_field(thd, key_part->field, key_buff + maybe_null, @@ -10526,9 +10527,9 @@ free_tmp_table(THD *thd, TABLE *entry) if (entry->file) { if (entry->db_stat) - entry->file->drop_table(entry->s->table_name.str); + entry->file->ha_drop_table(entry->s->table_name.str); else - entry->file->delete_table(entry->s->table_name.str); + entry->file->ha_delete_table(entry->s->table_name.str); delete entry->file; } @@ -10585,7 +10586,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, if (open_tmp_table(&new_table)) goto err1; if (table->file->indexes_are_disabled()) - new_table.file->disable_indexes(HA_KEY_SWITCH_ALL); + new_table.file->ha_disable_indexes(HA_KEY_SWITCH_ALL); table->file->ha_index_or_rnd_end(); table->file->ha_rnd_init(1); if (table->no_rows) @@ -10614,13 +10615,13 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, */ while (!table->file->rnd_next(new_table.record[1])) { - write_err= new_table.file->write_row(new_table.record[1]); + write_err= new_table.file->ha_write_row(new_table.record[1]); DBUG_EXECUTE_IF("raise_error", write_err= HA_ERR_FOUND_DUPP_KEY ;); if (write_err) goto err; } /* copy row that filled HEAP table */ - if ((write_err=new_table.file->write_row(table->record[0]))) + if ((write_err=new_table.file->ha_write_row(table->record[0]))) { if (new_table.file->is_fatal_error(write_err, HA_CHECK_DUP) || !ignore_last_dupp_key_error) @@ -10651,7 +10652,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, (void) table->file->ha_rnd_end(); (void) new_table.file->close(); err1: - new_table.file->delete_table(new_table.s->table_name.str); + new_table.file->ha_delete_table(new_table.s->table_name.str); err2: delete new_table.file; thd_proc_info(thd, save_proc_info); @@ -12093,7 +12094,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { int error; join->found_records++; - if ((error=table->file->write_row(table->record[0]))) + if ((error=table->file->ha_write_row(table->record[0]))) { if (!table->file->is_fatal_error(error, HA_CHECK_DUP)) goto end; @@ -12155,8 +12156,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { /* Update old record */ restore_record(table,record[1]); update_tmptable_sum_func(join->sum_funcs,table); - if ((error=table->file->update_row(table->record[1], - table->record[0]))) + if ((error=table->file->ha_update_row(table->record[1], + table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ @@ -12179,7 +12180,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } init_tmptable_sum_functions(join->sum_funcs); copy_funcs(join->tmp_table_param.items_to_copy); - if ((error=table->file->write_row(table->record[0]))) + if ((error=table->file->ha_write_row(table->record[0]))) { if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) @@ -12215,7 +12216,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), copy_fields(&join->tmp_table_param); // Groups are copied twice. copy_funcs(join->tmp_table_param.items_to_copy); - if (!(error=table->file->write_row(table->record[0]))) + if (!(error=table->file->ha_write_row(table->record[0]))) join->send_records++; // New group else { @@ -12231,8 +12232,8 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } restore_record(table,record[1]); update_tmptable_sum_func(join->sum_funcs,table); - if ((error=table->file->update_row(table->record[1], - table->record[0]))) + if ((error=table->file->ha_update_row(table->record[1], + table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ @@ -12275,7 +12276,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), join->sum_funcs_end[send_group_parts]); if (!join->having || join->having->val_int()) { - int error= table->file->write_row(table->record[0]); + int error= table->file->ha_write_row(table->record[0]); if (error && create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) @@ -13190,7 +13191,8 @@ check_reverse_order: select->quick=tmp; } } - else if (tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts) + else if (tab->type != JT_NEXT && + tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts) { /* SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC @@ -13503,7 +13505,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, } if (having && !having->val_int()) { - if ((error=file->delete_row(record))) + if ((error=file->ha_delete_row(record))) goto err; error=file->rnd_next(record); continue; @@ -13530,7 +13532,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, } if (compare_record(table, first_field) == 0) { - if ((error=file->delete_row(record))) + if ((error=file->ha_delete_row(record))) goto err; } else if (!found) @@ -13629,7 +13631,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, } if (having && !having->val_int()) { - if ((error=file->delete_row(record))) + if ((error=file->ha_delete_row(record))) goto err; continue; } @@ -13646,7 +13648,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, if (hash_search(&hash, org_key_pos, key_length)) { /* Duplicated found ; Remove the row */ - if ((error=file->delete_row(record))) + if ((error=file->ha_delete_row(record))) goto err; } else @@ -15670,7 +15672,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table_arg) item->save_in_result_field(1); } copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); - if ((write_error= table_arg->file->write_row(table_arg->record[0]))) + if ((write_error= table_arg->file->ha_write_row(table_arg->record[0]))) { if (create_myisam_from_heap(thd, table_arg, &tmp_table_param, write_error, 0)) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 177e84ab0a7..ee0a6d3c2ab 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5871,7 +5871,7 @@ bool get_schema_tables_result(JOIN *join, { table_list->table->file->extra(HA_EXTRA_NO_CACHE); table_list->table->file->extra(HA_EXTRA_RESET_STATE); - table_list->table->file->delete_all_rows(); + table_list->table->file->ha_delete_all_rows(); free_io_cache(table_list->table); filesort_free_buffers(table_list->table,1); table_list->table->null_row= 0; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5bd7d446cbd..505bcd1b421 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -630,7 +630,7 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) } else { - if ((error= file->delete_table(ddl_log_entry->name))) + if ((error= file->ha_delete_table(ddl_log_entry->name))) { if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE) break; @@ -667,8 +667,8 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) } else { - if (file->rename_table(ddl_log_entry->from_name, - ddl_log_entry->name)) + if (file->ha_rename_table(ddl_log_entry->from_name, + ddl_log_entry->name)) break; } if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) @@ -1299,9 +1299,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) lpt->table_name, lpt->create_info, lpt->alter_info->create_list, lpt->key_count, lpt->key_info_buffer, lpt->table->file)) || - lpt->table->file->create_handler_files(shadow_path, NULL, - CHF_CREATE_FLAG, - lpt->create_info)) + lpt->table->file->ha_create_handler_files(shadow_path, NULL, + CHF_CREATE_FLAG, + lpt->create_info)) { my_delete(shadow_frm_name, MYF(0)); error= 1; @@ -1353,15 +1353,15 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) VOID(pthread_mutex_lock(&LOCK_open)); if (my_delete(frm_name, MYF(MY_WME)) || #ifdef WITH_PARTITION_STORAGE_ENGINE - lpt->table->file->create_handler_files(path, shadow_path, - CHF_DELETE_FLAG, NULL) || + lpt->table->file->ha_create_handler_files(path, shadow_path, + CHF_DELETE_FLAG, NULL) || deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || (sync_ddl_log(), FALSE) || #endif #ifdef WITH_PARTITION_STORAGE_ENGINE my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || - lpt->table->file->create_handler_files(path, shadow_path, - CHF_RENAME_FLAG, NULL)) + lpt->table->file->ha_create_handler_files(path, shadow_path, + CHF_RENAME_FLAG, NULL)) #else my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) #endif @@ -3718,14 +3718,14 @@ mysql_rename_table(handlerton *base, const char *old_db, to_base= lc_to; } - if (!file || !(error=file->rename_table(from_base, to_base))) + if (!file || !(error=file->ha_rename_table(from_base, to_base))) { if (!(flags & NO_FRM_RENAME) && rename_file_ext(from,to,reg_ext)) { error=my_errno; /* Restore old file name */ if (file) - file->rename_table(to_base, from_base); + file->ha_rename_table(to_base, from_base); } } delete file; @@ -4376,7 +4376,7 @@ send_result_message: if (!result_code) // recreation went ok { if ((table->table= open_ltable(thd, table, lock_type, 0)) && - ((result_code= table->table->file->analyze(thd, check_opt)) > 0)) + ((result_code= table->table->file->ha_analyze(thd, check_opt)) > 0)) result_code= 0; // analyze went ok } if (result_code) // either mysql_recreate_table or analyze failed @@ -4486,7 +4486,7 @@ bool mysql_backup_table(THD* thd, TABLE_LIST* table_list) "MySQL Administrator (mysqldump, mysql)"); DBUG_RETURN(mysql_admin_table(thd, table_list, 0, "backup", TL_READ, 0, 0, 0, 0, - &handler::backup, 0)); + &handler::ha_backup, 0)); } @@ -4498,7 +4498,7 @@ bool mysql_restore_table(THD* thd, TABLE_LIST* table_list) DBUG_RETURN(mysql_admin_table(thd, table_list, 0, "restore", TL_WRITE, 1, 1, 0, &prepare_for_restore, - &handler::restore, 0)); + &handler::ha_restore, 0)); } @@ -4519,7 +4519,7 @@ bool mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) DBUG_ENTER("mysql_optimize_table"); DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, "optimize", TL_WRITE, 1,0,0,0, - &handler::optimize, 0)); + &handler::ha_optimize, 0)); } @@ -4933,7 +4933,7 @@ bool mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) DBUG_ENTER("mysql_analyze_table"); DBUG_RETURN(mysql_admin_table(thd, tables, check_opt, "analyze", lock_type, 1, 0, 0, 0, - &handler::analyze, 0)); + &handler::ha_analyze, 0)); } @@ -4980,7 +4980,7 @@ mysql_discard_or_import_tablespace(THD *thd, DBUG_RETURN(-1); } - error=table->file->discard_or_import_tablespace(discard); + error= table->file->ha_discard_or_import_tablespace(discard); thd_proc_info(thd, "end"); @@ -5353,14 +5353,14 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, switch (keys_onoff) { case ENABLE: - error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); break; case LEAVE_AS_IS: if (!indexes_were_disabled) break; /* fall-through: disabled indexes */ case DISABLE: - error= table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); } if (error == HA_ERR_WRONG_COMMAND) @@ -6130,14 +6130,14 @@ view_err: wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); - error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); - error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; default: @@ -6545,7 +6545,7 @@ view_err: KEY_PART_INFO *part_end; DBUG_PRINT("info", ("No new_table, checking add/drop index")); - table->file->prepare_for_alter(); + table->file->ha_prepare_for_alter(); if (index_add_count) { /* The add_index() method takes an array of KEY structs. */ @@ -6763,8 +6763,8 @@ view_err: t_table= table; } /* Tell the handler that a new frm file is in place. */ - if (t_table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, - create_info)) + if (t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG, + create_info)) goto err_with_placeholders; if (thd->locked_tables && new_name == table_name && new_db == db) { @@ -7064,7 +7064,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, copy_ptr->do_copy(copy_ptr); } prev_insert_id= to->file->next_insert_id; - error=to->file->write_row(to->record[0]); + error=to->file->ha_write_row(to->record[0]); to->auto_increment_field_not_null= FALSE; if (error) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index a48cff82715..5f7e3c5b620 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -440,10 +440,10 @@ bool st_select_lex_unit::exec() { item->assigned(0); // We will reinit & rexecute unit item->reset(); - table->file->delete_all_rows(); + table->file->ha_delete_all_rows(); } /* re-enabling indexes for next subselect iteration */ - if (union_distinct && table->file->enable_indexes(HA_KEY_SWITCH_ALL)) + if (union_distinct && table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL)) { DBUG_ASSERT(0); } @@ -485,7 +485,7 @@ bool st_select_lex_unit::exec() sl->join->exec(); if (sl == union_distinct) { - if (table->file->disable_indexes(HA_KEY_SWITCH_ALL)) + if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL)) DBUG_RETURN(TRUE); table->no_keyread=1; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 78dea6b7cdb..4d075e3308d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -526,7 +526,9 @@ int mysql_update(THD *thd, init_read_record(&info,thd,table,select,0,1); updated= found= 0; - thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ + /* Generate an error when trying to set a NOT NULL field to NULL. */ + thd->count_cuted_fields= ignore ? CHECK_FIELD_WARN + : CHECK_FIELD_ERROR_FOR_NULL; thd->cuted_fields=0L; thd_proc_info(thd, "Updating"); @@ -623,9 +625,9 @@ int mysql_update(THD *thd, call then it should be included in the count of dup_key_found and error should be set to 0 (only if these errors are ignored). */ - error= table->file->bulk_update_row(table->record[1], - table->record[0], - &dup_key_found); + error= table->file->ha_bulk_update_row(table->record[1], + table->record[0], + &dup_key_found); limit+= dup_key_found; updated-= dup_key_found; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9cccc7c724e..c98228424a5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 177 shift/reduce conflicts. + Currently there are 169 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 177 +%expect 169 /* Comments for TOKENS. @@ -1204,7 +1204,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <table_list> join_table_list join_table - table_factor table_ref + table_factor table_ref esc_table_ref select_derived derived_table_list %type <date_time_type> date_time_type; @@ -1295,7 +1295,9 @@ END_OF_INPUT %type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt %type <NONE> sp_proc_stmt_statement sp_proc_stmt_return %type <NONE> sp_proc_stmt_if -%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled sp_proc_stmt_leave +%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled +%type <NONE> sp_labeled_block sp_unlabeled_block +%type <NONE> sp_proc_stmt_leave %type <NONE> sp_proc_stmt_iterate %type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close %type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt @@ -1956,6 +1958,8 @@ ev_sql_stmt_inner: | sp_proc_stmt_return | sp_proc_stmt_if | case_stmt_specification + | sp_labeled_block + | sp_unlabeled_block | sp_labeled_control | sp_proc_stmt_unlabeled | sp_proc_stmt_leave @@ -2530,6 +2534,8 @@ sp_proc_stmt: | sp_proc_stmt_return | sp_proc_stmt_if | case_stmt_specification + | sp_labeled_block + | sp_unlabeled_block | sp_labeled_control | sp_proc_stmt_unlabeled | sp_proc_stmt_leave @@ -2656,14 +2662,35 @@ sp_proc_stmt_leave: sp_instr_jump *i; uint ip= sp->instructions(); uint n; + /* + When jumping to a BEGIN-END block end, the target jump + points to the block hpop/cpop cleanup instructions, + so we should exclude the block context here. + When jumping to something else (i.e., SP_LAB_ITER), + there are no hpop/cpop at the jump destination, + so we should include the block context here for cleanup. + */ + bool exclusive= (lab->type == SP_LAB_BEGIN); - n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */ + n= ctx->diff_handlers(lab->ctx, exclusive); if (n) - sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); - n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */ + { + sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); + } + n= ctx->diff_cursors(lab->ctx, exclusive); if (n) - sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); + { + sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL) + MYSQL_YYABORT; + sp->add_instr(cpop); + } i= new sp_instr_jump(ip, ctx); + if (i == NULL) + MYSQL_YYABORT; sp->push_backpatch(i, lab); /* Jumping forward */ sp->add_instr(i); } @@ -2691,10 +2718,20 @@ sp_proc_stmt_iterate: n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) - sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); + { + sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n); + if (hpop == NULL) + MYSQL_YYABORT; + sp->add_instr(hpop); + } n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) - sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); + { + sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n); + if (cpop == NULL) + MYSQL_YYABORT; + sp->add_instr(cpop); + } i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ sp->add_instr(i); } @@ -2978,19 +3015,17 @@ sp_labeled_control: sp_unlabeled_control sp_opt_label { LEX *lex= Lex; + sp_label_t *lab= lex->spcont->pop_label(); if ($5.str) { - sp_label_t *lab= lex->spcont->find_label($5.str); - - if (!lab || - my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) + if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) { my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str); MYSQL_YYABORT; } } - lex->sphead->backpatch(lex->spcont->pop_label()); + lex->sphead->backpatch(lab); } ; @@ -2999,15 +3034,59 @@ sp_opt_label: | label_ident { $$= $1; } ; -sp_unlabeled_control: +sp_labeled_block: + label_ident ':' + { + LEX *lex= Lex; + sp_pcontext *ctx= lex->spcont; + sp_label_t *lab= ctx->find_label($1.str); + + if (lab) + { + my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str); + MYSQL_YYABORT; + } + + lab= lex->spcont->push_label($1.str, + lex->sphead->instructions()); + lab->type= SP_LAB_BEGIN; + } + sp_block_content sp_opt_label + { + LEX *lex= Lex; + sp_label_t *lab= lex->spcont->pop_label(); + + if ($5.str) + { + if (my_strcasecmp(system_charset_info, $5.str, lab->name) != 0) + { + my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str); + MYSQL_YYABORT; + } + } + } + ; + +sp_unlabeled_block: + { /* Unlabeled blocks get a secret label. */ + LEX *lex= Lex; + uint ip= lex->sphead->instructions(); + sp_label_t *lab= lex->spcont->push_label((char *)"", ip); + lab->type= SP_LAB_BEGIN; + } + sp_block_content + { + LEX *lex= Lex; + lex->spcont->pop_label(); + } + ; + +sp_block_content: BEGIN_SYM { /* QQ This is just a dummy for grouping declarations and statements together. No [[NOT] ATOMIC] yet, and we need to figure out how make it coexist with the existing BEGIN COMMIT/ROLLBACK. */ LEX *lex= Lex; - sp_label_t *lab= lex->spcont->last_label(); - - lab->type= SP_LAB_BEGIN; lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE); } sp_decls @@ -3027,7 +3106,10 @@ sp_unlabeled_control: $3.curs)); lex->spcont= ctx->pop_context(); } - | LOOP_SYM + ; + +sp_unlabeled_control: + LOOP_SYM sp_proc_stmts1 END LOOP_SYM { LEX *lex= Lex; @@ -7463,10 +7545,22 @@ join_table_list: derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); } ; +/* + The ODBC escape syntax for Outer Join is: '{' OJ join_table '}' + The parser does not define OJ as a token, any ident is accepted + instead in $2 (ident). Also, all productions from table_ref can + be escaped, not only join_table. Both syntax extensions are safe + and are ignored. +*/ +esc_table_ref: + table_ref { $$=$1; } + | '{' ident table_ref '}' { $$=$3; } + ; + /* Warning - may return NULL in case of incomplete SELECT */ derived_table_list: - table_ref { $$=$1; } - | derived_table_list ',' table_ref + esc_table_ref { $$=$1; } + | derived_table_list ',' esc_table_ref { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); } @@ -7631,25 +7725,6 @@ table_factor: MYSQL_YYABORT; Select->add_joined_table($$); } - | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref - ON - { - /* Change the current name resolution context to a local context. */ - if (push_new_name_resolution_context(YYTHD, $3, $7)) - MYSQL_YYABORT; - - } - expr '}' - { - LEX *lex= Lex; - MYSQL_YYABORT_UNLESS($3 && $7); - add_join_on($7,$10); - Lex->pop_context(); - $7->outer_join|=JOIN_TYPE_LEFT; - $$=$7; - if (!($$= lex->current_select->nest_last_join(lex->thd))) - MYSQL_YYABORT; - } | select_derived_init get_select_lex select_derived2 { LEX *lex= Lex; diff --git a/sql/unireg.cc b/sql/unireg.cc index aab3f5606a8..38f09a7946c 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -401,7 +401,7 @@ int rea_create_table(THD *thd, const char *path, DBUG_ASSERT(*fn_rext(frm_name)); if (thd->variables.keep_files_on_create) create_info->options|= HA_CREATE_KEEP_FILES; - if (file->create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) + if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) goto err_handler; if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, create_info,0)) @@ -409,7 +409,7 @@ int rea_create_table(THD *thd, const char *path, DBUG_RETURN(0); err_handler: - VOID(file->create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info)); + VOID(file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info)); my_delete(frm_name, MYF(0)); DBUG_RETURN(1); } /* rea_create_table */ diff --git a/strings/decimal.c b/strings/decimal.c index f457014b2b1..0559dd97613 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1601,9 +1601,21 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, x+=10; *buf1=powers10[pos]*(x-y); } - if (frac0 < 0) + /* + In case we're rounding e.g. 1.5e9 to 2.0e9, the decimal_digit_t's inside + the buffer are as follows. + + Before <1, 5e8> + After <2, 5e8> + + Hence we need to set the 2nd field to 0. + The same holds if we round 1.5e-9 to 2e-9. + */ + if (frac0 < frac1) { - dec1 *end=to->buf+intg0, *buf=buf1+1; + dec1 *buf= to->buf + ((scale == 0 && intg0 == 0) ? 1 : intg0 + frac0); + dec1 *end= to->buf + len; + while (buf < end) *buf++=0; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9284b2182b1..3776be79399 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15674,7 +15674,7 @@ static void test_mysql_insert_id() myquery(rc); res= mysql_insert_id(mysql); DIE_UNLESS(res == 0); - rc= mysql_query(mysql, "update t2 set f1=NULL where f1=14"); + rc= mysql_query(mysql, "update t2 set f1=0 where f1=14"); myquery(rc); res= mysql_insert_id(mysql); DIE_UNLESS(res == 0); |