diff options
47 files changed, 5535 insertions, 4973 deletions
diff --git a/Makefile.am b/Makefile.am index 60b4f9bd07c..55f54476212 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,7 @@ tags: test-pl test-force-pl test-full-pl test-force-full-pl test-force-pl-mem \ test-unit test-ps test-nr test-pr test-ns test-binlog-statement \ test-ext-funcs test-ext-rpl test-ext-partitions test-ext-jp \ - test-ext-stress test-ext test-embedded \ + test-ext-stress test-ext test-embedded test-reprepare \ test-fast test-fast-cursor test-fast-view test-fast-prepare \ test-full-qa @@ -111,6 +111,11 @@ test-embedded: echo "no program found for 'embedded' tests - skipped testing" ; \ fi +test-reprepare: + cd mysql-test ; \ + @PERL@ ./mysql-test-run.pl $(force) $(mem) --ps-protocol \ + --mysqld=--debug=+d,reprepare_each_statement + test: test-unit test-ns test-pr test-full: test test-nr test-ps diff --git a/include/my_global.h b/include/my_global.h index a9e381ee66f..6cfc4d67305 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -570,7 +570,7 @@ typedef unsigned short ushort; #define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1) #define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0) -#define swap_variables(t, a, b) { register t dummy; dummy= a; a= b; b= dummy; } +#define swap_variables(t, a, b) { t dummy; dummy= a; a= b; b= dummy; } #define test(a) ((a) ? 1 : 0) #define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) #define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) diff --git a/include/my_sys.h b/include/my_sys.h index eccb61f5b29..09c768cadb7 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -90,6 +90,9 @@ extern int NEAR my_errno; /* Last error in mysys */ #define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ #define ME_COLOUR2 ((2 << ME_HIGHBYTE)) #define ME_COLOUR3 ((3 << ME_HIGHBYTE)) +#define ME_FATALERROR 1024 /* Fatal statement error */ +#define ME_NO_WARNING_FOR_ERROR 2048 /* Don't push a warning for error */ +#define ME_NO_SP_HANDLER 4096 /* Don't call stored routine error handlers */ /* Bits in last argument to fn_format */ #define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 5cce8c6147c..591b76f61ad 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -285,7 +285,7 @@ static int emb_stmt_execute(MYSQL_STMT *stmt) my_bool res; int4store(header, stmt->stmt_id); - header[4]= (uchar)stmt->flags; + header[4]= (uchar) stmt->flags; thd= (THD*)stmt->mysql->thd; thd->client_param_count= stmt->param_count; thd->client_params= stmt->params; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index a56cce50259..16be3eb966d 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1218,6 +1218,12 @@ DROP USER mysqltest_1@localhost; DROP DATABASE db27878; use test; DROP TABLE t1; +# +# Bug#33275 Server crash when creating temporary table mysql.user +# +CREATE TEMPORARY TABLE mysql.user (id INT); +FLUSH PRIVILEGES; +DROP TABLE mysql.user; drop table if exists test; Warnings: Note 1051 Unknown table 'test' diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 8ecfe3b2094..c293956148f 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -249,4 +249,25 @@ set global slow_query_log_file= NULL; ERROR 42000: Variable 'slow_query_log_file' can't be set to the value of 'NULL' set global general_log_file= @old_general_log_file; set global slow_query_log_file= @old_slow_query_log_file; + +# -- +# -- Bug#32748: Inconsistent handling of assignments to +# -- general_log_file/slow_query_log_file. +# -- + +SET @general_log_file_saved = @@global.general_log_file; +SET @slow_query_log_file_saved = @@global.slow_query_log_file; + +SET GLOBAL general_log_file = 'bug32748.query.log'; +SET GLOBAL slow_query_log_file = 'bug32748.slow.log'; + +SHOW VARIABLES LIKE '%log_file'; +Variable_name Value +general_log_file bug32748.query.log +slow_query_log_file bug32748.slow.log + +SET GLOBAL general_log_file = @general_log_file_saved; +SET GLOBAL slow_query_log_file = @slow_query_log_file_saved; + +# -- End of Bug#32748. End of 5.1 tests diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 1c5f0e4dfd6..33849eefe7a 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -143,32 +143,32 @@ b char(30) ); insert into t5( a, b, c) values( 9, 'recreated table', 9); execute stmt2 ; -a b c -9 recreated table 9 +a c b +9 9 recreated table drop table t5 ; create table t5 ( a int primary key, b char(30), c int, -d timestamp default current_timestamp +d timestamp default '2008-02-23 09:23:45' ); insert into t5( a, b, c) values( 9, 'recreated table', 9); execute stmt2 ; -a b c -9 recreated table 9 +a b c d +9 recreated table 9 2008-02-23 09:23:45 drop table t5 ; create table t5 ( a int primary key, -d timestamp default current_timestamp, +d timestamp default '2008-02-23 09:23:45', b char(30), c int ); insert into t5( a, b, c) values( 9, 'recreated table', 9); execute stmt2 ; -a b c -9 recreated table 9 +a d b c +9 2008-02-23 09:23:45 recreated table 9 drop table t5 ; create table t5 ( @@ -189,7 +189,8 @@ f3 int ); insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); execute stmt2 ; -ERROR 42S22: Unknown column 'test.t5.a' in 'field list' +f1 f2 f3 +9 recreated table 9 drop table t5 ; prepare stmt1 from ' select * from t1 where a <= 2 ' ; execute stmt1 ; diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result index 531d29d219e..9e1db062368 100644 --- a/mysql-test/r/ps_ddl.result +++ b/mysql-test/r/ps_ddl.result @@ -1,543 +1,252 @@ -SELECT VARIABLE_VALUE from -INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' -into @base_count ; -set @expected = 0; +drop temporary table if exists t1, t2, t3; +drop table if exists t1, t2, t3; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists v1, v2; +create procedure p_verify_reprepare_count(expected int) +begin +declare old_reprepare_count int default @reprepare_count; +select variable_value from +information_schema.session_status where +variable_name='com_stmt_reprepare' + into @reprepare_count; +if old_reprepare_count + expected <> @reprepare_count then +select concat("Expected: ", expected, +", actual: ", @reprepare_count - old_reprepare_count) +as "ERROR"; +else +select '' as "SUCCESS"; +end if; +end| +set @reprepare_count= 0; +flush status; ===================================================================== -Testing 1: NOTHING -> TABLE transitions +Part 1: NOTHING -> TABLE transitions ===================================================================== -drop table if exists t1; -prepare stmt from 'select * from t1'; +prepare stmt from "select * from t1"; ERROR 42S02: Table 'test.t1' doesn't exist ===================================================================== -Testing 2: NOTHING -> TEMPORARY TABLE transitions +Part 2: NOTHING -> TEMPORARY TABLE transitions ===================================================================== ===================================================================== -Testing 3: NOTHING -> VIEW transitions +Part 3: NOTHING -> VIEW transitions ===================================================================== ===================================================================== -Testing 4: TABLE -> NOTHING transitions +Part 4: TABLE -> NOTHING transitions ===================================================================== -drop table if exists t4; -create table t4(a int); -prepare stmt from 'select * from t4'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t4; -execute stmt; -ERROR 42S02: Table 'test.t4' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42S02: Table 'test.t4' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +# Test 4-a: select ... from <table> +create table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +# Test 4-b: TABLE -> NOTHING by renaming the table +create table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +rename table t1 to t2; +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +drop table t2; ===================================================================== -Testing 5: TABLE -> TABLE (DDL) transitions +Part 5: TABLE -> TABLE (DDL) transitions ===================================================================== -drop table if exists t5; -create table t5(a int); -prepare stmt from 'select a from t5'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t5 add column (b int); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t5; +create table t1 (a int); +prepare stmt from "select a from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 add column (b int); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +deallocate prepare stmt; ===================================================================== -Testing 6: TABLE -> TABLE (TRIGGER) transitions +Part 6: TABLE -> TABLE (TRIGGER) transitions ===================================================================== -drop table if exists t6; -create table t6(a int); -prepare stmt from 'insert into t6(a) value (?)'; +# Test 6-a: adding a relevant trigger +create table t1 (a int); +prepare stmt from "insert into t1 (a) value (?)"; set @val=1; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + +create trigger t1_bi before insert on t1 for each row +set @message= new.a; set @val=2; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -create trigger t6_bi before insert on t6 for each row -begin -set @message= "t6_bi"; -end -$$ -set @message="none"; +call p_verify_reprepare_count(1); +SUCCESS + +select @message; +@message +2 set @val=3; -set @expected = @expected + 1; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi +3 +prepare stmt from "insert into t1 (a) value (?)"; set @val=4; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; +4 +# Test 6-b: adding an irrelevant trigger +create trigger t1_bd before delete on t1 for each row +set @message= old.a; set @val=5; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + select @message; @message -t6_bi -set @message="none"; +5 set @val=6; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi -create trigger t6_bd before delete on t6 for each row -begin -set @message= "t6_bd"; -end -$$ -set @message="none"; +6 +prepare stmt from "insert into t1 (a) value (?)"; set @val=7; -set @expected = @expected + 1; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi -set @message="none"; +7 +# Test 6-c: changing a relevant trigger +drop trigger t1_bi; +create trigger t1_bi before insert on t1 for each row +set @message= concat("new trigger: ", new.a); set @val=8; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + select @message; @message -t6_bi -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; +new trigger: 8 set @val=9; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi -set @message="none"; +new trigger: 9 +prepare stmt from "insert into t1 (a) value (?)"; set @val=10; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi -drop trigger t6_bi; -create trigger t6_bi before insert on t6 for each row -begin -set @message= "t6_bi (2)"; -end -$$ -set @message="none"; +new trigger: 10 +# Test 6-d: changing an irrelevant trigger +drop trigger t1_bd; set @val=11; -set @expected = @expected + 1; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + select @message; @message -t6_bi (2) +new trigger: 11 +Test 6-e: removing a relevant trigger +drop trigger t1_bi; set @val=12; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + select @message; @message -t6_bi (2) -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; +new trigger: 11 set @val=13; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -t6_bi (2) -set @message="none"; +new trigger: 11 +prepare stmt from "insert into t1 (a) value (?)"; set @val=14; execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -t6_bi (2) -drop trigger t6_bd; -create trigger t6_bd before delete on t6 for each row -begin -set @message= "t6_bd (2)"; -end -$$ -set @message="none"; -set @val=15; -set @expected = @expected + 1; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -t6_bi (2) -set @message="none"; -set @val=16; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -t6_bi (2) -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=17; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -t6_bi (2) -set @message="none"; -set @val=18; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -t6_bi (2) -drop trigger t6_bi; -set @message="none"; -set @val=19; -set @expected = @expected + 1; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -none -set @val=20; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -none -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=21; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + select @message; @message -none -set @val=22; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -none -drop trigger t6_bd; -set @val=23; -set @expected = @expected + 1; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -none -set @val=24; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select @message; -@message -none -select * from t6 order by a; +new trigger: 11 +select * from t1 order by a; a 1 2 @@ -553,1443 +262,815 @@ a 12 13 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -drop table t6; +drop table t1; +deallocate prepare stmt; ===================================================================== -Testing 7: TABLE -> TABLE (TRIGGER dependencies) transitions +Part 7: TABLE -> TABLE (TRIGGER dependencies) transitions ===================================================================== -drop table if exists t7_proc; -drop table if exists t7_func; -drop table if exists t7_view; -drop table if exists t7_table; -drop table if exists t7_dependent_table; -drop table if exists t7_table_trigger; -drop table if exists t7_audit; -drop procedure if exists audit_proc; -drop function if exists audit_func; -drop view if exists audit_view; -create table t7_proc(a int); -create table t7_func(a int); -create table t7_view(a int); -create table t7_table(a int); -create table t7_table_trigger(a int); -create table t7_audit(old_a int, new_a int, reason varchar(50)); -create table t7_dependent_table(old_a int, new_a int, reason varchar(50)); -create procedure audit_proc(a int) -insert into t7_audit values (NULL, a, "proc v1"); -create function audit_func() returns varchar(50) -return "func v1"; -create view audit_view as select "view v1" as reason from dual; -create trigger t7_proc_bi before insert on t7_proc for each row -call audit_proc(NEW.a); -create trigger t7_func_bi before insert on t7_func for each row -insert into t7_audit values (NULL, NEW.a, audit_func()); -create trigger t7_view_bi before insert on t7_view for each row -insert into t7_audit values (NULL, NEW.a, (select reason from audit_view)); -create trigger t7_table_bi before insert on t7_table for each row -insert into t7_dependent_table values (NULL, NEW.a, "dependent table"); -create trigger t7_table_trigger_bi before insert on t7_dependent_table -for each row set NEW.reason="trigger v1"; -prepare stmt_proc from 'insert into t7_proc(a) value (?)'; -set @val=101; -execute stmt_proc using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=102; -execute stmt_proc using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure audit_proc; -create procedure audit_proc(a int) -insert into t7_audit values (NULL, a, "proc v2"); -set @val=103; -set @expected = @expected + 1; -execute stmt_proc using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=104; -execute stmt_proc using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_func from 'insert into t7_func(a) value (?)'; -set @val=201; -execute stmt_func using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=202; -execute stmt_func using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function audit_func; -create function audit_func() returns varchar(50) -return "func v2"; -set @val=203; -set @expected = @expected + 1; -execute stmt_func using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=204; -execute stmt_func using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_view from 'insert into t7_view(a) value (?)'; -set @val=301; -execute stmt_view using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=302; -execute stmt_view using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view audit_view; -create view audit_view as select "view v2" as reason from dual; -set @val=303; -set @expected = @expected + 1; -execute stmt_view using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=304; -execute stmt_view using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_table from 'insert into t7_table(a) value (?)'; -set @val=401; -execute stmt_table using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=402; -execute stmt_table using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t7_dependent_table add column comments varchar(100) default NULL; -set @val=403; -set @expected = @expected + 1; -execute stmt_table using @val; -ERROR 21S01: Column count doesn't match value count at row 1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=404; -set @expected = @expected + 1; -execute stmt_table using @val; -ERROR 21S01: Column count doesn't match value count at row 1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t7_dependent_table drop column comments; -set @val=405; -set @expected = @expected + 1; -execute stmt_table using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=406; -execute stmt_table using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_table_trigger from 'insert into t7_table(a) value (?)'; -set @val=501; -execute stmt_table_trigger using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=502; -execute stmt_table_trigger using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop trigger t7_table_trigger_bi; -create trigger t7_table_trigger_bi before insert on t7_dependent_table -for each row set NEW.reason="trigger v2"; -set @val=503; -set @expected = @expected + 1; -execute stmt_table_trigger using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=504; -execute stmt_table_trigger using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select * from t7_audit order by new_a; -old_a new_a reason -NULL 101 proc v1 -NULL 102 proc v1 -NULL 103 proc v2 -NULL 104 proc v2 -NULL 201 func v1 -NULL 202 func v1 -NULL 203 func v2 -NULL 204 func v2 -NULL 301 view v1 -NULL 302 view v1 -NULL 303 view v1 -NULL 304 view v1 -select * from t7_dependent_table order by new_a; -old_a new_a reason -NULL 401 trigger v1 -NULL 402 trigger v1 -NULL 405 trigger v1 -NULL 406 trigger v1 -NULL 501 trigger v1 -NULL 502 trigger v1 -NULL 503 trigger v2 -NULL 504 trigger v2 -drop table t7_proc; -drop table t7_func; -drop table t7_view; -drop table t7_table; -drop table t7_dependent_table; -drop table t7_table_trigger; -drop table t7_audit; -drop procedure audit_proc; -drop function audit_func; -drop view audit_view; +# Test 7-a: dependent PROCEDURE has changed +# +# Note, this scenario is not supported, subject of Bug#12093 +# +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row +call p1(new.a); +create procedure p1(a int) begin end; +prepare stmt from "insert into t1 (a) values (?)"; +set @var= 1; +execute stmt using @var; +drop procedure p1; +create procedure p1 (a int) begin end; +set @var= 2; +execute stmt using @var; +ERROR 42000: PROCEDURE test.p1 does not exist +# Cleanup +drop procedure p1; +call p_verify_reprepare_count(0); +SUCCESS + +# Test 7-b: dependent FUNCTION has changed +# +# Note, this scenario is not supported, subject of Bug#12093 +# +drop trigger t1_ai; +create trigger t1_ai after insert on t1 for each row +select f1(new.a+1) into @var; +create function f1 (a int) returns int return a; +prepare stmt from "insert into t1(a) values (?)"; +set @var=3; +execute stmt using @var; +select @var; +@var +4 +drop function f1; +create function f1 (a int) returns int return 0; +execute stmt using @var; +ERROR 42000: FUNCTION test.f1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +drop function f1; +deallocate prepare stmt; +# Test 7-c: dependent VIEW has changed +# +# Note, this scenario is not functioning correctly, see +# Bug#33255 Trigger using views and view ddl : corrupted triggers +# and Bug #33000 Triggers do not detect changes in meta-data. +# +drop trigger t1_ai; +create table t2 (a int unique); +create table t3 (a int unique); +create view v1 as select a from t2; +create trigger t1_ai after insert on t1 for each row +insert into v1 (a) values (new.a); +# Demonstrate that the same bug is present +# without prepared statements +insert into t1 (a) values (5); +select * from t2; +a +5 +select * from t3; +a +drop view v1; +create view v1 as select a from t3; +insert into t1 (a) values (6); +ERROR 42S02: Table 'test.t2' doesn't exist +flush table t1; +insert into t1 (a) values (6); +select * from t2; +a +5 +select * from t3; +a +6 +prepare stmt from "insert into t1 (a) values (?)"; +set @var=7; +execute stmt using @var; +call p_verify_reprepare_count(0); +SUCCESS + +select * from t3; +a +6 +7 +select * from t2; +a +5 +drop view v1; +create view v1 as select a from t2; +set @var=8; +execute stmt using @var; +call p_verify_reprepare_count(0); +SUCCESS + +# +# Sic: the insert went into t3, even though the view now +# points at t2. This is because neither the merged view +# nor its prelocking list are affected by view DDL +# The binary log is of course wrong, since it is not +# using prepared statements +# +select * from t2; +a +5 +select * from t3; +a +6 +7 +8 +flush table t1; +set @var=9; +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t2; +a +5 +9 +select * from t3; +a +6 +7 +8 +drop view v1; +drop table t1,t2,t3; +# Test 7-d: dependent TABLE has changed +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row +insert into t2 (a) values (new.a); +create table t2 (a int); +prepare stmt from "insert into t1 (a) values (?)"; +set @var=1; +execute stmt using @var; +alter table t2 add column comment varchar(255); +set @var=2; +# Since the dependent table is tracked in the prelocked +# list of the prepared statement, invalidation happens +# and the statement is re-prepared. This is an unnecessary +# side effect, since the statement that *is* dependent +# on t2 definition is inside the trigger, and it is currently +# not reprepared (see the previous test case). +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t1; +a +1 +2 +select * from t2; +a comment +1 NULL +2 NULL +drop table t1,t2; +# Test 7-e: dependent TABLE TRIGGER has changed +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row +insert into t2 (a) values (new.a); +create table t2 (a int unique); +create trigger t2_ai after insert on t2 for each row +insert into t3 (a) values (new.a); +create table t3 (a int unique); +create table t4 (a int unique); +insert into t1 (a) values (1); +select * from t1 join t2 on (t1.a=t2.a) join t3 on (t2.a=t3.a); +a a a +1 1 1 +drop trigger t2_ai; +create trigger t2_ai after insert on t2 for each row +insert into t4 (a) values (new.a); +insert into t1 (a) values (2); +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); +a a a +2 2 2 +prepare stmt from "insert into t1 (a) values (?)"; +set @var=3; +execute stmt using @var; +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); +a a a +2 2 2 +3 3 3 +drop trigger t2_ai; +create trigger t2_ai after insert on t2 for each row +insert into t3 (a) values (new.a); +set @var=4; +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t1 join t2 on (t1.a=t2.a) join t3 on (t2.a=t3.a); +a a a +1 1 1 +4 4 4 +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); +a a a +2 2 2 +3 3 3 +drop table t1, t2, t3, t4; +deallocate prepare stmt; ===================================================================== -Testing 8: TABLE -> TEMPORARY TABLE transitions +Part 8: TABLE -> TEMPORARY TABLE transitions ===================================================================== -drop table if exists t8; -create table t8(a int); -prepare stmt from 'select * from t8'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t8; -create temporary table t8(a int); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t8; +# Test 8-a: base table used recreated as temporary table +create table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +drop table t1; +create temporary table t1 (a int); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +deallocate prepare stmt; +# Test 8-b: temporary table has precedence over base table with same name +create table t1 (a int); +prepare stmt from 'select count(*) from t1'; +execute stmt; +count(*) +0 +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +count(*) +0 +call p_verify_reprepare_count(0); +SUCCESS + +create temporary table t1 AS SELECT 1; +execute stmt; +count(*) +1 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +count(*) +1 +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +drop temporary table t1; +drop table t1; ===================================================================== -Testing 9: TABLE -> VIEW transitions +Part 9: TABLE -> VIEW transitions ===================================================================== -drop table if exists t9; -drop table if exists t9_b; -create table t9(a int); -create table t9_b(a int); -prepare stmt from 'select * from t9'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t9; -create view t9 as select * from t9_b; -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t9; -drop table t9_b; +create table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +create table t2 (a int); +create view t1 as select * from t2; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +drop view t1; +drop table t2; +deallocate prepare stmt; ===================================================================== -Testing 10: TEMPORARY TABLE -> NOTHING transitions +Part 10: TEMPORARY TABLE -> NOTHING transitions ===================================================================== -drop temporary table if exists t10; -create temporary table t10(a int); -prepare stmt from 'select * from t10'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop temporary table t10; -execute stmt; -ERROR 42S02: Table 'test.t10' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42S02: Table 'test.t10' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +create temporary table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t1; +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; ===================================================================== -Testing 11: TEMPORARY TABLE -> TABLE transitions +Part 11: TEMPORARY TABLE -> TABLE transitions ===================================================================== -drop table if exists t11; -drop temporary table if exists t11; -create table t11(a int); -insert into t11(a) value (1); -create temporary table t11(a int); -prepare stmt from 'select * from t11'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop temporary table t11; -set @expected = @expected + 1; +# Test 11-a: temporary table replaced by base table +create table t1 (a int); +insert into t1 (a) value (1); +create temporary table t1 (a int); +prepare stmt from "select * from t1"; execute stmt; a -1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t1; execute stmt; a 1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select * from t11; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t1; a 1 -drop table t11; +drop table t1; +deallocate prepare stmt; +# Test 11-b: temporary table has precedence over base table with same name +# temporary table disappears +create table t1 (a int); +create temporary table t1 as select 1 as a; +prepare stmt from "select count(*) from t1"; +execute stmt; +count(*) +1 +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +count(*) +1 +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t1; +execute stmt; +count(*) +0 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +count(*) +0 +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +drop table t1; ===================================================================== -Testing 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions +Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions ===================================================================== -drop temporary table if exists t12; -create temporary table t12(a int); -prepare stmt from 'select a from t12'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop temporary table t12; -create temporary table t12(a int, b int); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select * from t12; +create temporary table t1 (a int); +prepare stmt from "select a from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t1; +create temporary table t1 (a int, b int); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +select * from t1; a b -drop table t12; +drop temporary table t1; +deallocate prepare stmt; ===================================================================== -Testing 13: TEMPORARY TABLE -> VIEW transitions +Part 13: TEMPORARY TABLE -> VIEW transitions ===================================================================== -drop temporary table if exists t13; -drop table if exists t13_b; -create temporary table t13(a int); -create table t13_b(a int); -prepare stmt from 'select * from t13'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop temporary table t13; -create view t13 as select * from t13_b; -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t13; -drop table t13_b; +create temporary table t1 (a int); +create table t2 (a int); +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t1; +create view t1 as select * from t2; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +drop view t1; +drop table t2; +deallocate prepare stmt; ===================================================================== -Testing 14: VIEW -> NOTHING transitions +Part 14: VIEW -> NOTHING transitions ===================================================================== -drop view if exists t14; -drop table if exists t14_b; -create table t14_b(a int); -create view t14 as select * from t14_b; -prepare stmt from 'select * from t14'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t14; -set @expected = @expected + 1; -execute stmt; -ERROR 42S02: Table 'test.t14' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR 42S02: Table 'test.t14' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t14_b; +create table t2 (a int); +create view t1 as select * from t2; +prepare stmt from "select * from t1"; +execute stmt; +a +drop view t1; +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +deallocate prepare stmt; ===================================================================== -Testing 15: VIEW -> TABLE transitions +Part 15: VIEW -> TABLE transitions ===================================================================== -drop view if exists t15; -drop table if exists t15_b; -create table t15_b(a int); -create view t15 as select * from t15_b; -prepare stmt from 'select * from t15'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t15; -create table t15(a int); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t15_b; -drop table t15; +create table t2 (a int); +create view t1 as select * from t2; +prepare stmt from "select * from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop view t1; +create table t1 (a int); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +drop table t2; +drop table t1; +deallocate prepare stmt; ===================================================================== -Testing 16: VIEW -> TEMPORARY TABLE transitions +Part 16: VIEW -> TEMPORARY TABLE transitions ===================================================================== -drop view if exists t16; -drop table if exists t16_b; -create table t16_b(a int); -create view t16 as select * from t16_b; -prepare stmt from 'select * from t16'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t16; -create temporary table t16(a int); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t16_b; -drop temporary table t16; +create table t2 (a int); +insert into t2 (a) values (1); +create view t1 as select * from t2; +prepare stmt from "select * from t1"; +execute stmt; +a +1 +call p_verify_reprepare_count(0); +SUCCESS + +create temporary table t1 (a int); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +drop view t1; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +drop temporary table t1; +deallocate prepare stmt; ===================================================================== -Testing 17: VIEW -> VIEW (DDL) transitions +Part 17: VIEW -> VIEW (DDL) transitions ===================================================================== -drop view if exists t17; -drop table if exists t17_b; -create table t17_b(a int); -insert into t17_b values (10), (20), (30); -create view t17 as select a, 2*a as b, 3*a as c from t17_b; -select * from t17; -a b c -10 20 30 -20 40 60 -30 60 90 -prepare stmt from 'select * from t17'; -execute stmt; +create table t2 (a int); +insert into t2 values (10), (20), (30); +create view t1 as select a, 2*a as b, 3*a as c from t2; +select * from t1; a b c 10 20 30 20 40 60 30 60 90 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +prepare stmt from "select * from t1"; execute stmt; a b c 10 20 30 20 40 60 30 60 90 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view t17; -create view t17 as select a, 2*a as b, 5*a as c from t17_b; -select * from t17; +drop view t1; +create view t1 as select a, 2*a as b, 5*a as c from t2; +select * from t1; a b c 10 20 50 20 40 100 30 60 150 -set @expected = @expected + 1; +# Currently a different result from conventional statements. +# A view is inlined once at prepare, later on view DDL +# does not affect prepared statement and it is not re-prepared. +# This is reported in Bug#36002 Prepared statements: if a view +# used in a statement is replaced, bad data execute stmt; a b c -10 20 50 -20 40 100 -30 60 150 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +10 20 30 +20 40 60 +30 60 90 +call p_verify_reprepare_count(0); +SUCCESS + +flush table t2; execute stmt; a b c 10 20 50 20 40 100 30 60 150 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t17_b; -drop view t17; +call p_verify_reprepare_count(1); +SUCCESS + +drop table t2; +drop view t1; +deallocate prepare stmt; ===================================================================== -Testing 18: VIEW -> VIEW (VIEW dependencies) transitions +Part 18: VIEW -> VIEW (VIEW dependencies) transitions ===================================================================== -drop table if exists t18; -drop table if exists t18_dependent_table; -drop view if exists t18_func; -drop view if exists t18_view; -drop view if exists t18_table; -drop function if exists view_func; -drop view if exists view_view; -create table t18(a int); -insert into t18 values (1), (2), (3); -create function view_func(x int) returns int -return x+1; -create view view_view as select "view v1" as reason from dual; -create table t18_dependent_table(a int); -create view t18_func as select a, view_func(a) as b from t18; -create view t18_view as select a, reason as b from t18, view_view; -create view t18_table as select * from t18; -prepare stmt_func from 'select * from t18_func'; -execute stmt_func; -a b -1 2 -2 3 -3 4 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_func; -a b -1 2 -2 3 -3 4 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function view_func; -create function view_func(x int) returns int -return x*x; -set @expected = @expected + 1; -execute stmt_func; -a b -1 1 -2 4 -3 9 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_func; -a b -1 1 -2 4 -3 9 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_view from 'select * from t18_view'; -execute stmt_view; -a b -1 view v1 -2 view v1 -3 view v1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_view; -a b -1 view v1 -2 view v1 -3 view v1 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop view view_view; -create view view_view as select "view v2" as reason from dual; -set @expected = @expected + 1; -execute stmt_view; -a b -1 view v2 -2 view v2 -3 view v2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_view; -a b -1 view v2 -2 view v2 -3 view v2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -prepare stmt_table from 'select * from t18_table'; -execute stmt_table; +# Part 18a: dependent function has changed +create table t1 (a int); +insert into t1 (a) values (1), (2), (3); +create function f1() returns int return (select max(a) from t1); +create view v1 as select f1(); +prepare stmt from "select * from v1"; +execute stmt; +f1() +3 +execute stmt; +f1() +3 +call p_verify_reprepare_count(0); +SUCCESS + +drop function f1; +create function f1() returns int return 2; +# XXX: Bug#12093. We only get a different error +# message because the non-existing procedure error is masked +# by the view. +execute stmt; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +execute stmt; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +call p_verify_reprepare_count(0); +SUCCESS + +# Part 18b: dependent procedure has changed (referred to via a function) +create table t2 (a int); +insert into t2 (a) values (4), (5), (6); +drop function f1; +create function f1() returns int +begin +declare x int; +call p1(x); +return x; +end| +create procedure p1(out x int) select max(a) from t1 into x; +prepare stmt from "select * from v1"; +execute stmt; +f1() +3 +execute stmt; +f1() +3 +call p_verify_reprepare_count(0); +SUCCESS + +drop procedure p1; +create procedure p1(out x int) select max(a) from t2 into x; +# XXX: bug. The prelocked list is not invalidated +# and we keep opening table t1, whereas the procedure +# is now referring to table t2 +execute stmt; +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +call p_verify_reprepare_count(0); +SUCCESS + +flush table t1; +execute stmt; +f1() +6 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +f1() +6 +# Test 18-c: dependent VIEW has changed +drop view v1; +create view v2 as select a from t1; +create view v1 as select * from v2; +prepare stmt from "select * from v1"; +execute stmt; a 1 2 3 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_table; +execute stmt; a 1 2 3 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t18 add column comments varchar(50) default NULL; -set @expected = @expected + 1; -execute stmt_table; +call p_verify_reprepare_count(0); +SUCCESS + +drop view v2; +create view v2 as select a from t2; +execute stmt; a 1 2 3 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_table; +execute stmt; a 1 2 3 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t18; -drop table t18_dependent_table; -drop view t18_func; -drop view t18_view; -drop view t18_table; -drop function view_func; -drop view view_view; +call p_verify_reprepare_count(0); +SUCCESS + +flush table t1; +execute stmt; +a +4 +5 +6 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +4 +5 +6 +# Test 18-d: dependent TABLE has changed +drop view v2; +create table v2 as select * from t1; +execute stmt; +a +1 +2 +3 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +1 +2 +3 +call p_verify_reprepare_count(0); +SUCCESS + +drop table v2; +create table v2 (a int unique) as select * from t2; +execute stmt; +a +4 +5 +6 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +4 +5 +6 +call p_verify_reprepare_count(0); +SUCCESS + +# Test 18-e: dependent TABLE trigger has changed +prepare stmt from "insert into v1 (a) values (?)"; +set @var= 7; +execute stmt using @var; +call p_verify_reprepare_count(0); +SUCCESS + +create trigger v2_bi before insert on v2 for each row set @message="v2_bi"; +set @var=8; +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select @message; +@message +v2_bi +drop trigger v2_bi; +set @message=null; +set @var=9; +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select @message; +@message +NULL +create trigger v2_bi after insert on v2 for each row set @message="v2_ai"; +set @var= 10; +execute stmt using @var; +call p_verify_reprepare_count(1); +SUCCESS + +select @message; +@message +v2_ai +select * from v1; +a +4 +5 +6 +7 +8 +9 +10 +# Cleanup +drop table if exists t1, t2, v1, v2; +drop view if exists v1, v2; +drop function f1; +drop procedure p1; +deallocate prepare stmt; ===================================================================== -Testing 19: Special tables (INFORMATION_SCHEMA) +Part 19: Special tables (INFORMATION_SCHEMA) ===================================================================== -drop procedure if exists proc_19; prepare stmt from -'select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE +"select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE from INFORMATION_SCHEMA.ROUTINES where - routine_name=\'proc_19\''; -create procedure proc_19() select "hi there"; + routine_name='p1'"; +create procedure p1() select "hi there"; execute stmt; ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE -test proc_19 PROCEDURE -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +test p1 PROCEDURE execute stmt; ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE -test proc_19 PROCEDURE -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure proc_19; -create procedure proc_19() select "hi there, again"; +test p1 PROCEDURE +drop procedure p1; +create procedure p1() select "hi there, again"; execute stmt; ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE -test proc_19 PROCEDURE -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +test p1 PROCEDURE execute stmt; ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE -test proc_19 PROCEDURE -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure proc_19; +test p1 PROCEDURE +call p_verify_reprepare_count(0); +SUCCESS + +drop procedure p1; +deallocate prepare stmt; ===================================================================== -Testing 20: Special tables (log tables) +Part 20: Special tables (log tables) ===================================================================== prepare stmt from -'select * from mysql.general_log where argument=\'IMPOSSIBLE QUERY STRING\''; -execute stmt; -event_time user_host thread_id server_id command_type argument -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -event_time user_host thread_id server_id command_type argument -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -event_time user_host thread_id server_id command_type argument -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -event_time user_host thread_id server_id command_type argument -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +"select * from mysql.general_log where argument='IMPOSSIBLE QUERY STRING'"; +execute stmt; +execute stmt; +execute stmt; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; ===================================================================== -Testing 21: Special tables (system tables) +Part 21: Special tables (system tables) ===================================================================== -drop procedure if exists proc_21; prepare stmt from -'select type, db, name from mysql.proc where name=\'proc_21\''; -create procedure proc_21() select "hi there"; +"select type, db, name from mysql.proc where name='p1'"; +create procedure p1() select "hi there"; execute stmt; type db name -PROCEDURE test proc_21 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +PROCEDURE test p1 execute stmt; type db name -PROCEDURE test proc_21 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure proc_21; -create procedure proc_21() select "hi there, again"; +PROCEDURE test p1 +drop procedure p1; +create procedure p1() select "hi there, again"; execute stmt; type db name -PROCEDURE test proc_21 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +PROCEDURE test p1 execute stmt; type db name -PROCEDURE test proc_21 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure proc_21; +PROCEDURE test p1 +call p_verify_reprepare_count(0); +SUCCESS + +drop procedure p1; +deallocate prepare stmt; ===================================================================== -Testing 22: Special tables (views temp tables) +Part 22: Special tables (views temp tables) ===================================================================== -drop table if exists t22_b; -drop view if exists t22; -create table t22_b(a int); -create algorithm=temptable view t22 as select a*a as a2 from t22_b; -show create view t22; +create table t1 (a int); +create algorithm=temptable view v1 as select a*a as a2 from t1; +# Using a temporary table internally should not confuse the prepared +# statement code, and should not raise ER_PS_INVALIDATED errors +show create view v1; View Create View character_set_client collation_connection -t22 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `t22` AS select (`t22_b`.`a` * `t22_b`.`a`) AS `a2` from `t22_b` latin1 latin1_swedish_ci -prepare stmt from 'select * from t22'; -insert into t22_b values (1), (2), (3); +v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (`t1`.`a` * `t1`.`a`) AS `a2` from `t1` latin1 latin1_swedish_ci +prepare stmt from "select * from v1"; +insert into t1 values (1), (2), (3); execute stmt; a2 1 4 9 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; a2 1 4 9 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -insert into t22_b values (4), (5), (6); +insert into t1 values (4), (5), (6); execute stmt; a2 1 @@ -1998,16 +1079,6 @@ a2 16 25 36 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; a2 1 @@ -2016,1333 +1087,291 @@ a2 16 25 36 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t22_b; -drop view t22; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +drop view v1; ===================================================================== -Testing 23: Special tables (internal join tables) +Part 23: Special statements ===================================================================== -drop table if exists t23_a; -drop table if exists t23_b; -create table t23_a(a int); -create table t23_b(b int); -prepare stmt from 'select * from t23_a join t23_b'; -insert into t23_a values (1), (2), (3); -insert into t23_b values (10), (20), (30); +# SQLCOM_ALTER_TABLE: +create table t1 (a int); +prepare stmt from "alter table t1 add column b int"; execute stmt; -a b -1 10 -2 10 -3 10 -1 20 -2 20 -3 20 -1 30 -2 30 -3 30 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +drop table t1; +create table t1 (a1 int, a2 int); +# t1 has changed, and it's does not lead to reprepare execute stmt; -a b -1 10 -2 10 -3 10 -1 20 -2 20 -3 20 -1 30 -2 30 -3 30 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -insert into t23_a values (4); -insert into t23_b values (40); +alter table t1 drop column b; execute stmt; -a b -1 10 -2 10 -3 10 -4 10 -1 20 -2 20 -3 20 -4 20 -1 30 -2 30 -3 30 -4 30 -1 40 -2 40 -3 40 -4 40 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +alter table t1 drop column b; execute stmt; -a b -1 10 -2 10 -3 10 -4 10 -1 20 -2 20 -3 20 -4 20 -1 30 -2 30 -3 30 -4 30 -1 40 -2 40 -3 40 -4 40 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t23_a; -drop table t23_b; -===================================================================== -Testing 24: Special statements -===================================================================== -drop table if exists t24_alter; -create table t24_alter(a int); -prepare stmt from 'alter table t24_alter add column b int'; -execute stmt; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_alter; -create table t24_alter(a1 int, a2 int); -execute stmt; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_alter drop column b; -execute stmt; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_alter drop column b; -execute stmt; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_alter; -drop table if exists t24_repair; -create table t24_repair(a int); -insert into t24_repair values (1), (2), (3); -prepare stmt from 'repair table t24_repair'; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +# SQLCOM_REPAIR: +create table t1 (a int); +insert into t1 values (1), (2), (3); +prepare stmt from "repair table t1"; execute stmt; Table Op Msg_type Msg_text -test.t24_repair repair status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_repair; -create table t24_repair(a1 int, a2 int); -insert into t24_repair values (1, 10), (2, 20), (3, 30); +test.t1 repair status OK execute stmt; Table Op Msg_type Msg_text -test.t24_repair repair status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_repair add column b varchar(50) default NULL; +test.t1 repair status OK +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); +# t1 has changed, and it's does not lead to reprepare execute stmt; Table Op Msg_type Msg_text -test.t24_repair repair status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_repair drop column b; +test.t1 repair status OK +alter table t1 add column b varchar(50) default NULL; execute stmt; Table Op Msg_type Msg_text -test.t24_repair repair status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_repair; -drop table if exists t24_analyze; -create table t24_analyze(a int); -insert into t24_analyze values (1), (2), (3); -prepare stmt from 'analyze table t24_analyze'; +test.t1 repair status OK +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 drop column b; execute stmt; Table Op Msg_type Msg_text -test.t24_analyze analyze status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_analyze; -create table t24_analyze(a1 int, a2 int); -insert into t24_analyze values (1, 10), (2, 20), (3, 30); +test.t1 repair status OK +call p_verify_reprepare_count(0); +SUCCESS + +# SQLCOM_ANALYZE: +prepare stmt from "analyze table t1"; execute stmt; Table Op Msg_type Msg_text -test.t24_analyze analyze status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_analyze add column b varchar(50) default NULL; +test.t1 analyze status OK +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); +# t1 has changed, and it's not a problem execute stmt; Table Op Msg_type Msg_text -test.t24_analyze analyze status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_analyze drop column b; +test.t1 analyze status OK +alter table t1 add column b varchar(50) default NULL; execute stmt; Table Op Msg_type Msg_text -test.t24_analyze analyze status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_analyze; -drop table if exists t24_optimize; -create table t24_optimize(a int); -insert into t24_optimize values (1), (2), (3); -prepare stmt from 'optimize table t24_optimize'; +test.t1 analyze status OK +alter table t1 drop column b; execute stmt; Table Op Msg_type Msg_text -test.t24_optimize optimize status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_optimize; -create table t24_optimize(a1 int, a2 int); -insert into t24_optimize values (1, 10), (2, 20), (3, 30); +test.t1 analyze status OK +call p_verify_reprepare_count(0); +SUCCESS + +# SQLCOM_OPTIMIZE: +prepare stmt from "optimize table t1"; execute stmt; Table Op Msg_type Msg_text -test.t24_optimize optimize status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_optimize add column b varchar(50) default NULL; +test.t1 optimize status Table is already up to date +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); +# t1 has changed, and it's not a problem execute stmt; Table Op Msg_type Msg_text -test.t24_optimize optimize status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t24_optimize drop column b; +test.t1 optimize status OK +alter table t1 add column b varchar(50) default NULL; execute stmt; Table Op Msg_type Msg_text -test.t24_optimize optimize status OK -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_optimize; -drop procedure if exists changing_proc; -prepare stmt from 'show create procedure changing_proc'; -execute stmt; -ERROR 42000: PROCEDURE changing_proc does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42000: PROCEDURE changing_proc does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -create procedure changing_proc() begin end; -execute stmt; -Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation -changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`() -begin end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation -changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`() -begin end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure changing_proc; -create procedure changing_proc(x int, y int) begin end; -execute stmt; -Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation -changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`(x int, y int) -begin end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation -changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`(x int, y int) -begin end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop procedure changing_proc; -execute stmt; -ERROR 42000: PROCEDURE changing_proc does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42000: PROCEDURE changing_proc does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function if exists changing_func; -prepare stmt from 'show create function changing_func'; -execute stmt; -ERROR 42000: FUNCTION changing_func does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42000: FUNCTION changing_func does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -create function changing_func() returns int return 0; -execute stmt; -Function sql_mode Create Function character_set_client collation_connection Database Collation -changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`() RETURNS int(11) -return 0 latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Function sql_mode Create Function character_set_client collation_connection Database Collation -changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`() RETURNS int(11) -return 0 latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function changing_func; -create function changing_func(x int, y int) returns int return x+y; -execute stmt; -Function sql_mode Create Function character_set_client collation_connection Database Collation -changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`(x int, y int) RETURNS int(11) -return x+y latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Function sql_mode Create Function character_set_client collation_connection Database Collation -changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`(x int, y int) RETURNS int(11) -return x+y latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function changing_func; -execute stmt; -ERROR 42000: FUNCTION changing_func does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -ERROR 42000: FUNCTION changing_func does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table if exists t24_trigger; -create table t24_trigger(a int); -prepare stmt from 'show create trigger t24_bi;'; +test.t1 optimize status OK +alter table t1 drop column b; +execute stmt; +Table Op Msg_type Msg_text +test.t1 optimize status OK +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +# SQLCOM_SHOW_CREATE_PROC: +prepare stmt from "show create procedure p1"; +execute stmt; +ERROR 42000: PROCEDURE p1 does not exist +execute stmt; +ERROR 42000: PROCEDURE p1 does not exist +create procedure p1() begin end; +execute stmt; +execute stmt; +drop procedure p1; +create procedure p1(x int, y int) begin end; +execute stmt; +execute stmt; +drop procedure p1; +execute stmt; +ERROR 42000: PROCEDURE p1 does not exist +execute stmt; +ERROR 42000: PROCEDURE p1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +# SQLCOM_SHOW_CREATE_FUNC: +prepare stmt from "show create function f1"; +execute stmt; +ERROR 42000: FUNCTION f1 does not exist +execute stmt; +ERROR 42000: FUNCTION f1 does not exist +create function f1() returns int return 0; +execute stmt; +execute stmt; +drop function f1; +create function f1(x int, y int) returns int return x+y; +execute stmt; +execute stmt; +drop function f1; +execute stmt; +ERROR 42000: FUNCTION f1 does not exist +execute stmt; +ERROR 42000: FUNCTION f1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +# SQLCOM_SHOW_CREATE_TRIGGER: +create table t1 (a int); +prepare stmt from "show create trigger t1_bi"; execute stmt; ERROR HY000: Trigger does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; ERROR HY000: Trigger does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -create trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi"; -end -$$ +create trigger t1_bi before insert on t1 for each row set @message= "t1_bi"; execute stmt; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi"; -end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi"; -end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop trigger t24_bi; -create trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi (2)"; -end -$$ -set @expected = @expected + 1; execute stmt; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi (2)"; -end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row -begin -set @message= "t24_bi (2)"; -end latin1 latin1_swedish_ci latin1_swedish_ci -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop trigger t24_bi; +drop trigger t1_bi; +create trigger t1_bi before insert on t1 for each row set @message= "t1_bi (2)"; +execute stmt; +execute stmt; +drop trigger t1_bi; execute stmt; ERROR HY000: Trigger does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; ERROR HY000: Trigger does not exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t24_trigger; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +deallocate prepare stmt; ===================================================================== -Testing 25: Testing the strength of TABLE_SHARE version +Part 24: Testing the strength of TABLE_SHARE version ===================================================================== -drop table if exists t25_num_col; -create table t25_num_col(a int); -prepare stmt from 'select a from t25_num_col'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_num_col add column b varchar(50) default NULL; -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_num_col; -drop table if exists t25_col_name; -create table t25_col_name(a int); -prepare stmt from 'select * from t25_col_name'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_col_name change a b int; -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_col_name; -drop table if exists t25_col_type; -create table t25_col_type(a int); -prepare stmt from 'select * from t25_col_type'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_col_type change a a varchar(10); -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_col_type; -drop table if exists t25_col_type_length; -create table t25_col_type_length(a varchar(10)); -prepare stmt from 'select * from t25_col_type_length'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_col_type_length change a a varchar(20); -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_col_type_length; -drop table if exists t25_col_null; -create table t25_col_null(a varchar(10)); -prepare stmt from 'select * from t25_col_null'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_col_null change a a varchar(10) NOT NULL; -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_col_null; -drop table if exists t25_col_default; -create table t25_col_default(a int, b int DEFAULT 10); -prepare stmt from 'insert into t25_col_default(a) values (?)'; -set @val=1; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=2; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_col_default change b b int DEFAULT 20; -set @val=3; -set @expected = @expected + 1; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @val=4; -execute stmt using @val; -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -select * from t25_col_default; -a b -1 10 -2 10 -3 20 -4 20 -drop table t25_col_default; -drop table if exists t25_index; -create table t25_index(a varchar(10)); -prepare stmt from 'select * from t25_index'; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -create index i1 on t25_index(a); -set @expected = @expected + 1; -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt; -a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_index; -drop table if exists t25_index_unique; -create table t25_index_unique(a varchar(10), b varchar(10)); -create index i1 on t25_index_unique(a, b); -show create table t25_index_unique; -Table Create Table -t25_index_unique CREATE TABLE `t25_index_unique` ( - `a` varchar(10) DEFAULT NULL, - `b` varchar(10) DEFAULT NULL, - KEY `i1` (`a`,`b`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -prepare stmt from 'select * from t25_index_unique'; +# Test 24-a: number of columns +create table t1 (a int); +prepare stmt from "select a from t1"; execute stmt; -a b -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +a +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 add column b varchar(50) default NULL; execute stmt; -a b -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -alter table t25_index_unique drop index i1; -create unique index i1 on t25_index_unique(a, b); -show create table t25_index_unique; -Table Create Table -t25_index_unique CREATE TABLE `t25_index_unique` ( - `a` varchar(10) DEFAULT NULL, - `b` varchar(10) DEFAULT NULL, - UNIQUE KEY `i1` (`a`,`b`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -set @expected = @expected + 1; +a +call p_verify_reprepare_count(1); +SUCCESS + execute stmt; -a b -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-b: column name +alter table t1 change b c int; execute stmt; -a b -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop table t25_index_unique; -===================================================================== -Testing reported bugs -===================================================================== -drop table if exists table_12093; -drop function if exists func_12093; -drop function if exists func_12093_unrelated; -drop procedure if exists proc_12093; -create table table_12093(a int); -create function func_12093() -returns int -begin -return (select count(*) from table_12093); -end// -create procedure proc_12093(a int) -begin -select * from table_12093; -end// -create function func_12093_unrelated() returns int return 2; -create procedure proc_12093_unrelated() begin end; -prepare stmt_sf from 'select func_12093();'; -prepare stmt_sp from 'call proc_12093(func_12093())'; -execute stmt_sf; -func_12093() -0 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_sp; a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function func_12093_unrelated; -drop procedure proc_12093_unrelated; -execute stmt_sf; -func_12093() -0 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_sp; +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_sf; -func_12093() -0 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -execute stmt_sp; +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-c: column type +alter table t1 change a a varchar(10); +execute stmt; a -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -deallocate prepare stmt_sf; -deallocate prepare stmt_sp; -drop table table_12093; -drop function func_12093; -drop procedure proc_12093; -drop function if exists func_21294; -create function func_21294() returns int return 10; -prepare stmt from "select func_21294()"; -execute stmt; -func_21294() -10 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function func_21294; -create function func_21294() returns int return 10; -execute stmt; -func_21294() -10 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -drop function func_21294; -create function func_21294() returns int return 20; -set @expected = @expected + 1; -execute stmt; -func_21294() -20 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-d: column type length +alter table t1 change a a varchar(20); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-e: column NULL property +alter table t1 change a a varchar(20) NOT NULL; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-f: column DEFAULT +alter table t1 change c c int DEFAULT 20; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-g: number of keys +create unique index t1_a_idx on t1 (a); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Test 24-h: changing index uniqueness +drop index t1_a_idx on t1; +create index t1_a_idx on t1 (a); +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +# Cleanup +drop table t1; deallocate prepare stmt; -drop function func_21294; +===================================================================== +Testing reported bugs +===================================================================== +# +# Bug#27420 A combination of PS and view operations cause +# error + assertion on shutdown +# drop table if exists t_27420_100; drop table if exists t_27420_101; drop view if exists v_27420; @@ -3353,55 +1382,36 @@ insert into t_27420_101 values (1), (2); create view v_27420 as select t_27420_100.a X, t_27420_101.a Y from t_27420_100, t_27420_101 where t_27420_100.a=t_27420_101.a; -prepare stmt from 'select * from v_27420'; +prepare stmt from "select * from v_27420"; execute stmt; X Y 1 1 2 2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + drop view v_27420; create table v_27420(X int, Y int); -set @expected = @expected + 1; execute stmt; X Y -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + drop table v_27420; create table v_27420 (a int, b int, filler char(200)); -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -deallocate prepare stmt; +execute stmt; +a b filler +call p_verify_reprepare_count(1); +SUCCESS + drop table t_27420_100; drop table t_27420_101; drop table v_27420; +deallocate prepare stmt; +# +# Bug#27430 Crash in subquery code when in PS and table DDL changed +# after PREPARE +# drop table if exists t_27430_1; drop table if exists t_27430_2; create table t_27430_1 (a int not null, oref int not null, key(a)); @@ -3417,43 +1427,20 @@ insert into t_27430_2 values (2, 2), (1234, 3), (1234, 4); -prepare stmt from -'select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2'; -execute stmt; -oref a Z -1 1 1 -2 2 0 -3 1234 0 -4 1234 0 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +prepare stmt from +"select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2"; execute stmt; oref a Z 1 1 1 2 2 0 3 1234 0 4 1234 0 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + drop table t_27430_1, t_27430_2; create table t_27430_1 (a int, oref int, key(a)); -insert into t_27430_1 values +insert into t_27430_1 values (1, 1), (1, NULL), (2, 3), @@ -3465,35 +1452,22 @@ insert into t_27430_2 values (2,2), (NULL, 3), (NULL, 4); -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -set @expected = @expected + 1; -execute stmt; -ERROR HY000: Prepared statement result set has changed, rebind needed -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -deallocate prepare stmt; +execute stmt; +oref a Z +1 1 1 +2 2 0 +3 NULL NULL +4 NULL 0 +call p_verify_reprepare_count(1); +SUCCESS + drop table t_27430_1; drop table t_27430_2; +deallocate prepare stmt; +# +# Bug#27690 Re-execution of prepared statement after table +# was replaced with a view crashes +# drop table if exists t_27690_1; drop view if exists v_27690_1; drop table if exists v_27690_2; @@ -3501,66 +1475,28 @@ create table t_27690_1 (a int, b int); insert into t_27690_1 values (1,1),(2,2); create table v_27690_1 as select * from t_27690_1; create table v_27690_2 as select * from t_27690_1; -prepare stmt from 'select * from v_27690_1, v_27690_2'; +prepare stmt from "select * from v_27690_1, v_27690_2"; execute stmt; a b a b 1 1 1 1 2 2 1 1 1 1 2 2 2 2 2 2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; a b a b 1 1 1 1 2 2 1 1 1 1 2 2 2 2 2 2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 drop table v_27690_1; execute stmt; ERROR 42S02: Table 'test.v_27690_1' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 execute stmt; ERROR 42S02: Table 'test.v_27690_1' doesn't exist -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(0); +SUCCESS + create view v_27690_1 as select A.a, A.b from t_27690_1 A, t_27690_1 B; -set @expected = @expected + 1; execute stmt; a b a b 1 1 1 1 @@ -3571,16 +1507,9 @@ a b a b 2 2 2 2 1 1 2 2 2 2 2 2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 +call p_verify_reprepare_count(1); +SUCCESS + execute stmt; a b a b 1 1 1 1 @@ -3591,17 +1520,693 @@ a b a b 2 2 2 2 1 1 2 2 2 2 2 2 -SELECT CASE (VARIABLE_VALUE - @base_count - @expected) -WHEN 0 THEN "PASSED" - ELSE "FAILED" - END -AS `CHECK`, -(VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS -where variable_name='COM_STMT_REPREPARE' ; -CHECK OFFSET -PASSED 0 -deallocate prepare stmt; +call p_verify_reprepare_count(0); +SUCCESS + drop table t_27690_1; drop view v_27690_1; drop table v_27690_2; +deallocate prepare stmt; +#===================================================================== +# TODO: fix the below two bugs and modify their tests +# +# Bug#21294 Executing a prepared statement that executes +# a stored function which was recreat +# +create function f1() returns int return 10; +prepare stmt from "select f1()"; +execute stmt; +f1() +10 +drop function f1; +create function f1() returns int return 10; +execute stmt; +ERROR 42000: FUNCTION test.f1 does not exist +drop function f1; +create function f1() returns int return 20; +execute stmt; +ERROR 42000: FUNCTION test.f1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +drop function f1; +deallocate prepare stmt; +# +# Bug#12093 SP not found on second PS execution if another thread drops +# other SP in between +# +drop table if exists t_12093; +drop function if exists f_12093; +drop function if exists f_12093_unrelated; +drop procedure if exists p_12093; +create table t_12093 (a int); +create function f_12093() returns int return (select count(*) from t_12093); +create procedure p_12093(a int) select * from t_12093; +create function f_12093_unrelated() returns int return 2; +create procedure p_12093_unrelated() begin end; +prepare stmt_sf from 'select f_12093();'; +prepare stmt_sp from 'call p_12093(f_12093())'; +execute stmt_sf; +f_12093() +0 +execute stmt_sp; +a +drop function f_12093_unrelated; +drop procedure p_12093_unrelated; +# XXX: bug +execute stmt_sf; +ERROR 42000: FUNCTION test.f_12093 does not exist +# XXX: bug +execute stmt_sp; +ERROR 42000: PROCEDURE test.p_12093 does not exist +# XXX: bug +execute stmt_sf; +ERROR 42000: FUNCTION test.f_12093 does not exist +# XXX: bug +execute stmt_sp; +ERROR 42000: PROCEDURE test.p_12093 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +drop table t_12093; +drop function f_12093; +drop procedure p_12093; +deallocate prepare stmt_sf; +deallocate prepare stmt_sp; +===================================================================== +Ensure that metadata validation is performed for every type of +SQL statement where it is needed. +===================================================================== +# +# SQLCOM_SELECT +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "select 1 as res from dual where (1) in (select * from t1)"; +drop table t1; +create table t1 (x int); +execute stmt; +res +drop table t1; +deallocate prepare stmt; +call p_verify_reprepare_count(1); +SUCCESS + +# +# SQLCOM_CREATE_TABLE +# +drop table if exists t1; +drop table if exists t2; +create table t1 (a int); +prepare stmt from 'create table t2 as select * from t1'; +execute stmt; +drop table t2; +execute stmt; +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S01: Table 't2' already exists +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +ERROR 42S01: Table 't2' already exists +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +create temporary table t2 (a int); +execute stmt; +ERROR 42S01: Table 't2' already exists +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +ERROR 42S01: Table 't2' already exists +call p_verify_reprepare_count(0); +SUCCESS + +drop temporary table t2; +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +create view t2 as select 1; +execute stmt; +Got one of the listed errors +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +Got one of the listed errors +call p_verify_reprepare_count(0); +SUCCESS + +drop view t2; +drop table t1; +create table t1 (x varchar(20)); +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t2; +x +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +alter table t1 add column y decimal(10,3); +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t2; +x y +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +deallocate prepare stmt; +# XXX: no validation of the first table in case of +# CREATE TEMPORARY TABLE. This is a shortcoming of the current code, +# but since validation is not strictly necessary, nothing is done +# about it. +# Will be fixed as part of work on Bug#21431 "Incomplete support of +# temporary tables" +create table t1 (a int); +insert into t1 (a) values (1); +prepare stmt from "create temporary table if not exists t2 as select * from t1"; +execute stmt; +drop table t2; +execute stmt; +execute stmt; +Warnings: +Note 1050 Table 't2' already exists +select * from t2; +a +1 +1 +execute stmt; +Warnings: +Note 1050 Table 't2' already exists +select * from t2; +a +1 +1 +1 +drop table t2; +create temporary table t2 (a varchar(10)); +execute stmt; +Warnings: +Note 1050 Table 't2' already exists +select * from t2; +a +1 +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +create table t1 (x int); +execute stmt; +Warnings: +Note 1050 Table 't2' already exists +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +Warnings: +Note 1050 Table 't2' already exists +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +drop temporary table t2; +drop table t2; +deallocate prepare stmt; +create table t1 (a int); +prepare stmt from "create table t2 like t1"; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +drop table t1; +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +create table t1 (x char(17)); +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t2; +alter table t1 add column y time; +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +select * from t2; +x y +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +drop table t2; +deallocate prepare stmt; +# +# SQLCOM_UPDATE +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "update t2 set a=a+1 where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_INSERT +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "insert into t2 set a=((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_INSERT_SELECT +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "insert into t2 select * from t1"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_REPLACE +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "replace t2 set a=((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_REPLACE_SELECT +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "replace t2 select * from t1"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_DELETE +# +drop table if exists t1, t2; +create table t1 (a int); +create table t2 (a int); +prepare stmt from "delete from t2 where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; +# +# SQLCOM_DELETE_MULTI +# +drop table if exists t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +prepare stmt from "delete t2, t3 from t2, t3 where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2, t3; +deallocate prepare stmt; +# +# SQLCOM_UPDATE_MULTI +# +drop table if exists t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +prepare stmt from "update t2, t3 set t3.a=t2.a, t2.a=null where (1) in (select * from t1)"; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2, t3; +deallocate prepare stmt; +# Intermediate results: 8 SQLCOMs tested, 8 automatic reprepares +call p_verify_reprepare_count(8); +SUCCESS + +# +# SQLCOM_LOAD +# +drop table if exists t1; +create table t1 (a varchar(20)); +prepare stmt from "load data infile '../std_data_ln/words.dat' into table t1"; +ERROR HY000: This command is not supported in the prepared statement protocol yet +drop table t1; +# +# SQLCOM_SHOW_DATABASES +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show databases where (1) in (select * from t1)"; +execute stmt; +Database +drop table t1; +create table t1 (x int); +execute stmt; +Database +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_TABLES +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show tables where (1) in (select * from t1)"; +execute stmt; +Tables_in_test +drop table t1; +create table t1 (x int); +execute stmt; +Tables_in_test +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_FIELDS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show fields from t1 where (1) in (select * from t1)"; +execute stmt; +Field Type Null Key Default Extra +drop table t1; +create table t1 (x int); +execute stmt; +Field Type Null Key Default Extra +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_KEYS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show keys from t1 where (1) in (select * from t1)"; +execute stmt; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +drop table t1; +create table t1 (x int); +execute stmt; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_VARIABLES +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show variables where (1) in (select * from t1)"; +execute stmt; +Variable_name Value +drop table t1; +create table t1 (x int); +execute stmt; +Variable_name Value +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_STATUS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show status where (1) in (select * from t1)"; +execute stmt; +Variable_name Value +drop table t1; +create table t1 (x int); +execute stmt; +Variable_name Value +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_LOGS, +# SQLCOM_SHOW_ENGINE_MUTEX, SQLCOM_SHOW_PROCESSLIST +# +# Currently can not have a where clause, need to be covered +# with tests +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show engine all status where (1) in (select * from t1)"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1 +prepare stmt from "show engine all logs where (1) in (select * from t1)"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1 +prepare stmt from "show engine all mutex where (1) in (select * from t1)"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1 +prepare stmt from "show processlist where (1) in (select * from t1)"; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1 +drop table t1; +# +# SQLCOM_SHOW_CHARSETS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show charset where (1) in (select * from t1)"; +execute stmt; +Charset Description Default collation Maxlen +drop table t1; +create table t1 (x int); +execute stmt; +Charset Description Default collation Maxlen +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_COLLATIONS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show collation where (1) in (select * from t1)"; +execute stmt; +Collation Charset Id Default Compiled Sortlen +drop table t1; +create table t1 (x int); +execute stmt; +Collation Charset Id Default Compiled Sortlen +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_TABLE_STATUS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show table status where (1) in (select * from t1)"; +execute stmt; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +drop table t1; +create table t1 (x int); +execute stmt; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_TRIGGERS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show triggers where (1) in (select * from t1)"; +execute stmt; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +drop table t1; +create table t1 (x int); +execute stmt; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_OPEN_TABLES +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show open tables where (1) in (select * from t1)"; +execute stmt; +Database Table In_use Name_locked +drop table t1; +create table t1 (x int); +execute stmt; +Database Table In_use Name_locked +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_STATUS_PROC +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show procedure status where (1) in (select * from t1)"; +execute stmt; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +drop table t1; +create table t1 (x int); +execute stmt; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_STATUS_FUNC +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show function status where (1) in (select * from t1)"; +execute stmt; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +drop table t1; +create table t1 (x int); +execute stmt; +Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SHOW_EVENTS +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "show events where (1) in (select * from t1)"; +execute stmt; +Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation +drop table t1; +create table t1 (x int); +execute stmt; +Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_SET_OPTION +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "set @a=((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_DO +# +drop table if exists t1; +create table t1 (a int); +prepare stmt from "do ((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; +# +# SQLCOM_CALL +# +drop table if exists t1; +drop procedure if exists p1; +create procedure p1(a int) begin end; +create table t1 (a int); +prepare stmt from "call p1((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +drop procedure p1; +deallocate prepare stmt; +# +# SQLCOM_CREATE_VIEW +# +drop table if exists t1; +drop view if exists v1; +create table t1 (a int); +prepare stmt from "create view v1 as select * from t1"; +execute stmt; +drop view v1; +drop table t1; +create table t1 (x int); +execute stmt; +drop view v1; +drop table t1; +deallocate prepare stmt; +# Intermediate result: number of reprepares matches the number +# of tests +call p_verify_reprepare_count(18); +SUCCESS + +# +# SQLCOM_ALTER_VIEW +# +drop view if exists v1; +create view v1 as select 1; +prepare stmt from "alter view v1 as select 2"; +ERROR HY000: This command is not supported in the prepared statement protocol yet +drop view v1; +# Cleanup +# +drop temporary table if exists t1, t2, t3; +drop table if exists t1, t2, t3, v1, v2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists v1, v2; diff --git a/mysql-test/r/ps_ddl1.result b/mysql-test/r/ps_ddl1.result new file mode 100644 index 00000000000..87abcd90590 --- /dev/null +++ b/mysql-test/r/ps_ddl1.result @@ -0,0 +1,482 @@ +drop temporary table if exists t1; +drop table if exists t1, t2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists t1; +drop schema if exists mysqltest; +create procedure p_verify_reprepare_count(expected int) +begin +declare old_reprepare_count int default @reprepare_count; +select variable_value from +information_schema.session_status where +variable_name='com_stmt_reprepare' + into @reprepare_count; +if old_reprepare_count + expected <> @reprepare_count then +select concat("Expected: ", expected, +", actual: ", @reprepare_count - old_reprepare_count) +as "ERROR"; +else +select '' as "SUCCESS"; +end if; +end| +set @reprepare_count= 0; +flush status; +drop table if exists t1; +# Column added or dropped is not within the list of selected columns +# or table comment has changed. +# A reprepare is probably not needed. +create table t1 (a int, b int); +prepare stmt from "select a from t1"; +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 add column c int; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 drop column b; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 comment "My best table"; +execute stmt; +a +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +a +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +deallocate prepare stmt; +# Selects using the table at various positions, inser,update ... +# + the table disappears +create table t1 (a int); +prepare stmt1 from "truncate t1"; +prepare stmt2 from "select 1 as my_column from t1"; +prepare stmt3 from "select 1 as my_column from (select * from t1) as t2"; +prepare stmt4 from +"select 1 as my_column from (select 1) as t2 where exists (select 1 from t1)"; +prepare stmt5 from "select * from (select 1 as b) as t2, t1"; +prepare stmt6 from "select * from t1 union all select 1.5"; +prepare stmt7 from "select 1 as my_column union all select 1 from t1"; +prepare stmt8 from "insert into t1 values(1),(2)"; +prepare stmt9 from "update t1 set a = 3 where a = 2"; +prepare stmt10 from "delete from t1 where a = 1"; +# Attention: Result logging is disabled. +execute stmt10; +execute stmt9; +execute stmt8; +execute stmt7; +execute stmt6; +execute stmt5; +execute stmt4; +execute stmt3; +execute stmt2; +execute stmt1; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +execute stmt10; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt9; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt8; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt7; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt6; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt5; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt4; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt3; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt2; +ERROR 42S02: Table 'test.t1' doesn't exist +execute stmt1; +ERROR 42S02: Table 'test.t1' doesn't exist +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt10; +deallocate prepare stmt9; +deallocate prepare stmt8; +deallocate prepare stmt7; +deallocate prepare stmt6; +deallocate prepare stmt5; +deallocate prepare stmt4; +deallocate prepare stmt3; +deallocate prepare stmt2; +deallocate prepare stmt1; +# Selects using the table at various positions, inser,update ... +# + layout change (drop column) which must cause a reprepare +create table t1 (a int, b int); +insert into t1 values(1,1),(2,2),(3,3); +create table t2 like t1; +insert into t1 values(2,2); +prepare stmt1 from "select a,b from t1"; +prepare stmt2 from "select a,b from (select * from t1) as t1"; +prepare stmt3 from "select * from t1 where a = 2 and b = 2"; +prepare stmt4 from "select * from t2 where (a,b) in (select * from t1)"; +prepare stmt5 from "select * from t1 union select * from t2"; +prepare stmt6 from "select * from t1 union all select * from t2"; +prepare stmt7 from "insert into t1 set a = 4, b = 4"; +prepare stmt8 from "insert into t1 select * from t2"; +# Attention: Result logging is disabled. +execute stmt8; +execute stmt7; +execute stmt6; +execute stmt5; +execute stmt4; +execute stmt3; +execute stmt2; +execute stmt1; +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 drop column b; +execute stmt8; +ERROR 21S01: Column count doesn't match value count at row 1 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt7; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt6; +ERROR 21000: The used SELECT statements have a different number of columns +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt5; +ERROR 21000: The used SELECT statements have a different number of columns +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt4; +ERROR 21000: Operand should contain 2 column(s) +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt3; +ERROR 42S22: Unknown column 'b' in 'where clause' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt2; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt1; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt8; +ERROR 21S01: Column count doesn't match value count at row 1 +call p_verify_reprepare_count(1); +ERROR +Expected: 1, actual: 0 +execute stmt7; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt6; +ERROR 21000: The used SELECT statements have a different number of columns +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt5; +ERROR 21000: The used SELECT statements have a different number of columns +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt4; +ERROR 21000: Operand should contain 2 column(s) +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt3; +ERROR 42S22: Unknown column 'b' in 'where clause' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt2; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt1; +ERROR 42S22: Unknown column 'b' in 'field list' +call p_verify_reprepare_count(1); +SUCCESS + +# Why does the INSERT ... SELECT does not get a reprepare or is +# only the counter not incremented? +execute stmt8; +ERROR 21S01: Column count doesn't match value count at row 1 +call p_verify_reprepare_count(1); +ERROR +Expected: 1, actual: 0 +alter table t2 add column c int; +execute stmt8; +ERROR 21S01: Column count doesn't match value count at row 1 +call p_verify_reprepare_count(1); +SUCCESS + +deallocate prepare stmt8; +deallocate prepare stmt7; +deallocate prepare stmt6; +deallocate prepare stmt5; +deallocate prepare stmt4; +deallocate prepare stmt3; +deallocate prepare stmt2; +deallocate prepare stmt1; +drop table t1; +drop table t2; +# select AVG(<col>) + optimizer uses index meets loss of the index +create table t1 (a int, b int, primary key(b),unique index t1_unq_idx(a)); +insert into t1 set a = 0, b = 0; +insert into t1 select a + 1, b + 1 from t1; +insert into t1 select a + 2, b + 2 from t1; +insert into t1 select a + 4, b + 4 from t1; +insert into t1 select a + 8, b + 8 from t1; +# Optimizer strategy: Possible keys = NULL , Extra = Using index +prepare stmt from "select avg(a) from t1"; +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(0); +SUCCESS + +alter table t1 drop index t1_unq_idx; +# Optimizer strategy: Possible keys = NULL , Extra = +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(0); +SUCCESS + +# select AVG(<col>) + optimizer uses table scan meets a new index +alter table t1 add unique index t1_unq_idx(a); +# Optimizer strategy: Possible keys = NULL , Extra = Using index +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +avg(a) +7.5000 +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +drop table t1; +# table replaced by not updatable view - Insert +create table t1 (a int); +prepare stmt from "insert into t1 values(1)"; +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +drop table t1; +create view t1 as select 1; +execute stmt; +ERROR HY000: The target table t1 of the INSERT is not insertable-into +call p_verify_reprepare_count(1); +SUCCESS + +drop view t1; +create table t2 (a int); +create view t1 as select * from t2 with check option; +execute stmt; +call p_verify_reprepare_count(1); +SUCCESS + +execute stmt; +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +1 +deallocate prepare stmt; +drop view t1; +drop table t2; +===================================================================== +Some freestyle tests +===================================================================== +create temporary table t1 as select 1 as a; +create procedure p1() +begin +drop temporary table t1; +end| +create function f1() returns int +begin +call p1(); +return 1; +end| +prepare stmt from "select f1() as my_column, a from t1"; +execute stmt; +ERROR HY000: Can't reopen table: 't1' +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +prepare stmt from "select a, f1() as my_column from t1"; +execute stmt; +ERROR HY000: Can't reopen table: 't1' +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +prepare stmt from "select f1() as my_column, count(*) from t1"; +execute stmt; +ERROR HY000: Can't reopen table: 't1' +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +prepare stmt from "select count(*), f1() as my_column from t1"; +execute stmt; +ERROR HY000: Can't reopen table: 't1' +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +# Execute fails, no drop of temporary table +prepare stmt from "select 1 as my_column from (select 1) as t2 + where exists (select f1() from t1)"; +execute stmt; +my_column +1 +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +my_column +1 +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +# Execute drops temporary table +prepare stmt from "select f1()"; +execute stmt; +f1() +1 +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42S02: Unknown table 't1' +call p_verify_reprepare_count(0); +SUCCESS + +drop function f1; +drop procedure p1; +deallocate prepare stmt; +# Execute fails, temporary table is not replaced by another +create temporary table t1 as select 1 as a; +create procedure p1() +begin +drop temporary table t1; +create temporary table t1 as select 'abc' as a; +end| +create function f1() returns int +begin +call p1(); +return 1; +end| +prepare stmt from "select count(*), f1() as my_column from t1"; +execute stmt; +ERROR HY000: Can't reopen table: 't1' +call p_verify_reprepare_count(0); +SUCCESS + +select * from t1; +a +1 +deallocate prepare stmt; +prepare stmt from "call p1"; +execute stmt; +drop procedure p1; +create schema mysqltest; +create procedure mysqltest.p1() +begin +drop schema mysqltest; +create schema mysqltest; +end| +execute stmt; +ERROR 42000: PROCEDURE test.p1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +execute stmt; +ERROR 42000: PROCEDURE test.p1 does not exist +call p_verify_reprepare_count(0); +SUCCESS + +deallocate prepare stmt; +drop schema mysqltest; +drop temporary table t1; +# Cleanup +# +drop temporary table if exists t1; +drop table if exists t1, t2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists t1; +drop schema if exists mysqltest; diff --git a/mysql-test/r/query_cache_merge.result b/mysql-test/r/query_cache_merge.result index c6df4266de2..d2bbe217815 100644 --- a/mysql-test/r/query_cache_merge.result +++ b/mysql-test/r/query_cache_merge.result @@ -18,3 +18,4 @@ Variable_name Value Qcache_queries_in_cache 0 drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257,t00; SET @@global.query_cache_size=0; +set @@global.table_definition_cache=@save_table_definition_cache; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index e7f5c41513b..35d5134fa6b 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -820,7 +820,6 @@ call p1(); drop trigger t1_bi; create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id); execute stmt1; -ERROR 42S02: Table 'test.t3' doesn't exist call p1(); ERROR 42S02: Table 'test.t3' doesn't exist deallocate prepare stmt1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index e5c3c860c93..3f66599751d 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -1014,3 +1014,13 @@ Variable_name='table_lock_wait_timeout'; Variable_name Value table_definition_cache # table_lock_wait_timeout # + +# -- +# -- Bug#34820: log_output can be set to illegal value. +# -- +SET GLOBAL log_output = ''; +ERROR 42000: Variable 'log_output' can't be set to the value of '' +SET GLOBAL log_output = 0; +ERROR 42000: Variable 'log_output' can't be set to the value of '0' + +# -- End of Bug#34820. diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 85f9691e443..0f240e7eccf 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -10,7 +10,6 @@ # ############################################################################## federated_transactions : Bug#29523 Transactions do not work -ps_ddl : Bug#12093 2007-12-14 pending WL#4165 / WL#4166 csv_alter_table : Bug#33696 2008-01-21 pcrews no .result file - bug allows NULL columns in CSV tables user_limits : Bug#23921 random failure of user_limits.test status : Bug#32966 main.status fails diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index d00881bad99..3fac767468e 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1266,6 +1266,12 @@ DROP DATABASE db27878; use test; DROP TABLE t1; +--echo # +--echo # Bug#33275 Server crash when creating temporary table mysql.user +--echo # +CREATE TEMPORARY TABLE mysql.user (id INT); +FLUSH PRIVILEGES; +DROP TABLE mysql.user; # # Bug #33201 Crash occurs when granting update privilege on one column of a view # diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index a340238b724..2fd2cabc97c 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -231,6 +231,34 @@ set global slow_query_log_file= NULL; set global general_log_file= @old_general_log_file; set global slow_query_log_file= @old_slow_query_log_file; +########################################################################### + +--echo +--echo # -- +--echo # -- Bug#32748: Inconsistent handling of assignments to +--echo # -- general_log_file/slow_query_log_file. +--echo # -- + +--echo +SET @general_log_file_saved = @@global.general_log_file; +SET @slow_query_log_file_saved = @@global.slow_query_log_file; + +--echo +SET GLOBAL general_log_file = 'bug32748.query.log'; +SET GLOBAL slow_query_log_file = 'bug32748.slow.log'; + +--echo +SHOW VARIABLES LIKE '%log_file'; + +--echo +SET GLOBAL general_log_file = @general_log_file_saved; +SET GLOBAL slow_query_log_file = @slow_query_log_file_saved; + +--echo +--echo # -- End of Bug#32748. + +########################################################################### + --echo End of 5.1 tests --enable_ps_protocol diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 42bf39890de..95cbd908933 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -181,7 +181,7 @@ create table t5 a int primary key, b char(30), c int, - d timestamp default current_timestamp + d timestamp default '2008-02-23 09:23:45' ); insert into t5( a, b, c) values( 9, 'recreated table', 9); execute stmt2 ; @@ -191,7 +191,7 @@ drop table t5 ; create table t5 ( a int primary key, - d timestamp default current_timestamp, + d timestamp default '2008-02-23 09:23:45', b char(30), c int ); @@ -218,7 +218,6 @@ create table t5 f3 int ); insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); ---error 1054 execute stmt2 ; drop table t5 ; diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test index c824d17063b..e19e73df3ac 100644 --- a/mysql-test/t/ps_ddl.test +++ b/mysql-test/t/ps_ddl.test @@ -47,1793 +47,2025 @@ # - Part 20: Special tables (log tables) # - Part 21: Special tables (system tables) # - Part 22: Special tables (views temp tables) -# - Part 23: Special tables (internal join tables) -# - Part 24: Special statements -# - Part 25: Testing the strength of TABLE_SHARE version - -let $base_count = SELECT VARIABLE_VALUE from -INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' -into @base_count ; - -let $check = SELECT CASE (VARIABLE_VALUE - @base_count - @expected) - WHEN 0 THEN "PASSED" - ELSE "FAILED" - END - AS `CHECK`, - (VARIABLE_VALUE - @base_count - @expected) AS `OFFSET` - from INFORMATION_SCHEMA.SESSION_STATUS - where variable_name='COM_STMT_REPREPARE' ; - -eval $base_count; -set @expected = 0; - -# Maintainer: -# When not expecting a re-prepare, write the test like this: -# execute stmt; -# eval $check; -# -# When expecting a re-prepare, write the test like this: -# set @expected = @expected + 1; -# execute stmt; -# eval $check; -# +# - Part 23: Special statements +# - Part 24: Testing the strength of TABLE_SHARE version +--disable_warnings +drop temporary table if exists t1, t2, t3; +drop table if exists t1, t2, t3; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists v1, v2; +--enable_warnings + +delimiter |; +create procedure p_verify_reprepare_count(expected int) +begin + declare old_reprepare_count int default @reprepare_count; + + select variable_value from + information_schema.session_status where + variable_name='com_stmt_reprepare' + into @reprepare_count; + + if old_reprepare_count + expected <> @reprepare_count then + select concat("Expected: ", expected, + ", actual: ", @reprepare_count - old_reprepare_count) + as "ERROR"; + else + select '' as "SUCCESS"; + end if; +end| +delimiter ;| +set @reprepare_count= 0; +flush status; --echo ===================================================================== ---echo Testing 1: NOTHING -> TABLE transitions +--echo Part 1: NOTHING -> TABLE transitions --echo ===================================================================== ---disable_warnings -drop table if exists t1; ---enable_warnings - # can not be tested since prepare failed --error ER_NO_SUCH_TABLE -prepare stmt from 'select * from t1'; +prepare stmt from "select * from t1"; --echo ===================================================================== ---echo Testing 2: NOTHING -> TEMPORARY TABLE transitions +--echo Part 2: NOTHING -> TEMPORARY TABLE transitions --echo ===================================================================== # can not be tested --echo ===================================================================== ---echo Testing 3: NOTHING -> VIEW transitions +--echo Part 3: NOTHING -> VIEW transitions --echo ===================================================================== # can not be tested --echo ===================================================================== ---echo Testing 4: TABLE -> NOTHING transitions +--echo Part 4: TABLE -> NOTHING transitions --echo ===================================================================== ---disable_warnings -drop table if exists t4; ---enable_warnings +--echo # Test 4-a: select ... from <table> +create table t1 (a int); -create table t4(a int); +prepare stmt from "select * from t1"; +execute stmt; +call p_verify_reprepare_count(0); +execute stmt; +call p_verify_reprepare_count(0); + +drop table t1; +--error ER_NO_SUCH_TABLE +execute stmt; +call p_verify_reprepare_count(0); +--error ER_NO_SUCH_TABLE +execute stmt; +call p_verify_reprepare_count(0); +deallocate prepare stmt; -prepare stmt from 'select * from t4'; +--echo # Test 4-b: TABLE -> NOTHING by renaming the table +create table t1 (a int); +prepare stmt from "select * from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t4; +rename table t1 to t2; --error ER_NO_SUCH_TABLE execute stmt; -eval $check; +call p_verify_reprepare_count(0); --error ER_NO_SUCH_TABLE execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +deallocate prepare stmt; +drop table t2; --echo ===================================================================== ---echo Testing 5: TABLE -> TABLE (DDL) transitions +--echo Part 5: TABLE -> TABLE (DDL) transitions --echo ===================================================================== ---disable_warnings -drop table if exists t5; ---enable_warnings +create table t1 (a int); -create table t5(a int); - -prepare stmt from 'select a from t5'; +prepare stmt from "select a from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t5 add column (b int); +alter table t1 add column (b int); -set @expected = @expected + 1; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +drop table t1; +deallocate prepare stmt; -drop table t5; --echo ===================================================================== ---echo Testing 6: TABLE -> TABLE (TRIGGER) transitions +--echo Part 6: TABLE -> TABLE (TRIGGER) transitions --echo ===================================================================== -# -# Test 6-a: adding a relevant trigger -# Test 6-b: adding an irrelevant trigger -# Test 6-c: changing a relevant trigger -# Test 6-d: changing an irrelevant trigger -# Test 6-e: removing a relevant trigger -# Test 6-f: removing an irrelevant trigger -# - ---disable_warnings -drop table if exists t6; ---enable_warnings +--echo # Test 6-a: adding a relevant trigger -create table t6(a int); +create table t1 (a int); -prepare stmt from 'insert into t6(a) value (?)'; +prepare stmt from "insert into t1 (a) value (?)"; set @val=1; execute stmt using @val; -eval $check; -set @val=2; -execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); # Relevant trigger: execute should reprepare -delimiter $$; -create trigger t6_bi before insert on t6 for each row - begin - set @message= "t6_bi"; - end -$$ -delimiter ;$$ - -set @message="none"; +create trigger t1_bi before insert on t1 for each row + set @message= new.a; + +set @val=2; +execute stmt using @val; +call p_verify_reprepare_count(1); +select @message; set @val=3; -set @expected = @expected + 1; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; + +prepare stmt from "insert into t1 (a) value (?)"; set @val=4; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; +--echo # Test 6-b: adding an irrelevant trigger + +# Unrelated trigger: reprepare may or may not happen, implementation dependent +create trigger t1_bd before delete on t1 for each row + set @message= old.a; + set @val=5; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(1); select @message; -set @message="none"; set @val=6; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -# Unrelated trigger: execute can pass of fail, implementation dependent -delimiter $$; -create trigger t6_bd before delete on t6 for each row - begin - set @message= "t6_bd"; - end -$$ -delimiter ;$$ - -set @message="none"; +prepare stmt from "insert into t1 (a) value (?)"; set @val=7; -set @expected = @expected + 1; -execute stmt using @val; -eval $check; -select @message; -set @message="none"; -set @val=8; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=9; -execute stmt using @val; -eval $check; -select @message; -set @message="none"; -set @val=10; -execute stmt using @val; -eval $check; -select @message; +--echo # Test 6-c: changing a relevant trigger # Relevant trigger: execute should reprepare -drop trigger t6_bi; -delimiter $$; -create trigger t6_bi before insert on t6 for each row - begin - set @message= "t6_bi (2)"; - end -$$ -delimiter ;$$ - -set @message="none"; -set @val=11; -set @expected = @expected + 1; -execute stmt using @val; -eval $check; -select @message; -set @val=12; -execute stmt using @val; -eval $check; -select @message; +drop trigger t1_bi; +create trigger t1_bi before insert on t1 for each row + set @message= concat("new trigger: ", new.a); -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=13; +set @val=8; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(1); select @message; -set @message="none"; -set @val=14; +set @val=9; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -# Unrelated trigger: execute can pass of fail, implementation dependent -drop trigger t6_bd; -delimiter $$; -create trigger t6_bd before delete on t6 for each row - begin - set @message= "t6_bd (2)"; - end -$$ -delimiter ;$$ - -set @message="none"; -set @val=15; -set @expected = @expected + 1; -execute stmt using @val; -eval $check; -select @message; -set @message="none"; -set @val=16; +prepare stmt from "insert into t1 (a) value (?)"; +set @val=10; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=17; -execute stmt using @val; -eval $check; -select @message; -set @message="none"; -set @val=18; -execute stmt using @val; -eval $check; -select @message; +--echo # Test 6-d: changing an irrelevant trigger -drop trigger t6_bi; +# Unrelated trigger: reprepare may or may not happen, implementation dependent +drop trigger t1_bd; -set @message="none"; -set @val=19; -set @expected = @expected + 1; -execute stmt using @val; -eval $check; -select @message; -set @val=20; +set @val=11; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(1); select @message; -prepare stmt from 'insert into t6(a) value (?)'; -set @message="none"; -set @val=21; +--echo Test 6-e: removing a relevant trigger + +drop trigger t1_bi; + +set @val=12; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(1); select @message; -set @val=22; +set @val=13; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -drop trigger t6_bd; - -set @val=23; -set @expected = @expected + 1; -execute stmt using @val; -eval $check; -select @message; -set @val=24; +prepare stmt from "insert into t1 (a) value (?)"; +set @val=14; execute stmt using @val; -eval $check; +call p_verify_reprepare_count(0); select @message; -select * from t6 order by a; -drop table t6; +select * from t1 order by a; +drop table t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 7: TABLE -> TABLE (TRIGGER dependencies) transitions +--echo Part 7: TABLE -> TABLE (TRIGGER dependencies) transitions --echo ===================================================================== -# -# Test 7-a: dependent PROCEDURE has changed -# Test 7-b: dependent FUNCTION has changed -# Test 7-c: dependent VIEW has changed -# Test 7-d: dependent TABLE has changed -# Test 7-e: dependent TABLE TRIGGER has changed -# - ---disable_warnings -drop table if exists t7_proc; -drop table if exists t7_func; -drop table if exists t7_view; -drop table if exists t7_table; -drop table if exists t7_dependent_table; -drop table if exists t7_table_trigger; -drop table if exists t7_audit; -drop procedure if exists audit_proc; -drop function if exists audit_func; -drop view if exists audit_view; ---enable_warnings - -create table t7_proc(a int); -create table t7_func(a int); -create table t7_view(a int); -create table t7_table(a int); -create table t7_table_trigger(a int); - -create table t7_audit(old_a int, new_a int, reason varchar(50)); -create table t7_dependent_table(old_a int, new_a int, reason varchar(50)); - -create procedure audit_proc(a int) - insert into t7_audit values (NULL, a, "proc v1"); +--echo # Test 7-a: dependent PROCEDURE has changed +--echo # +--echo # Note, this scenario is not supported, subject of Bug#12093 +--echo # + +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row + call p1(new.a); +create procedure p1(a int) begin end; +prepare stmt from "insert into t1 (a) values (?)"; +set @var= 1; +execute stmt using @var; +drop procedure p1; +create procedure p1 (a int) begin end; +set @var= 2; +--error ER_SP_DOES_NOT_EXIST +execute stmt using @var; +--echo # Cleanup +drop procedure p1; +call p_verify_reprepare_count(0); + +--echo # Test 7-b: dependent FUNCTION has changed +--echo # +--echo # Note, this scenario is not supported, subject of Bug#12093 +--echo # +drop trigger t1_ai; +create trigger t1_ai after insert on t1 for each row + select f1(new.a+1) into @var; +create function f1 (a int) returns int return a; +prepare stmt from "insert into t1(a) values (?)"; +set @var=3; +execute stmt using @var; +select @var; +drop function f1; +create function f1 (a int) returns int return 0; +--error ER_SP_DOES_NOT_EXIST +execute stmt using @var; +call p_verify_reprepare_count(0); +drop function f1; +deallocate prepare stmt; -create function audit_func() returns varchar(50) - return "func v1"; - -create view audit_view as select "view v1" as reason from dual; - -create trigger t7_proc_bi before insert on t7_proc for each row - call audit_proc(NEW.a); - -create trigger t7_func_bi before insert on t7_func for each row - insert into t7_audit values (NULL, NEW.a, audit_func()); - -create trigger t7_view_bi before insert on t7_view for each row - insert into t7_audit values (NULL, NEW.a, (select reason from audit_view)); - -create trigger t7_table_bi before insert on t7_table for each row - insert into t7_dependent_table values (NULL, NEW.a, "dependent table"); - -create trigger t7_table_trigger_bi before insert on t7_dependent_table - for each row set NEW.reason="trigger v1"; - -prepare stmt_proc from 'insert into t7_proc(a) value (?)'; -set @val=101; -execute stmt_proc using @val; -eval $check; -set @val=102; -execute stmt_proc using @val; -eval $check; - -drop procedure audit_proc; - -create procedure audit_proc(a int) - insert into t7_audit values (NULL, a, "proc v2"); - -set @val=103; -set @expected = @expected + 1; -execute stmt_proc using @val; -eval $check; -set @val=104; -execute stmt_proc using @val; -eval $check; - - -prepare stmt_func from 'insert into t7_func(a) value (?)'; -set @val=201; -execute stmt_func using @val; -eval $check; -set @val=202; -execute stmt_func using @val; -eval $check; - -drop function audit_func; - -create function audit_func() returns varchar(50) - return "func v2"; - -set @val=203; -set @expected = @expected + 1; -execute stmt_func using @val; -eval $check; -set @val=204; -execute stmt_func using @val; -eval $check; - -prepare stmt_view from 'insert into t7_view(a) value (?)'; -set @val=301; -execute stmt_view using @val; -eval $check; -set @val=302; -execute stmt_view using @val; -eval $check; - -drop view audit_view; - -create view audit_view as select "view v2" as reason from dual; - -# Because of Bug#33255, the wrong result is still produced for cases -# 303 and 304, even after re-preparing the statement. -# This is because the table trigger is cached and is not invalidated. - -set @val=303; -set @expected = @expected + 1; -execute stmt_view using @val; -eval $check; -set @val=304; -execute stmt_view using @val; -eval $check; - - -prepare stmt_table from 'insert into t7_table(a) value (?)'; -set @val=401; -execute stmt_table using @val; -eval $check; -set @val=402; -execute stmt_table using @val; -eval $check; - -alter table t7_dependent_table add column comments varchar(100) default NULL; - -set @val=403; -set @expected = @expected + 1; ---error ER_WRONG_VALUE_COUNT_ON_ROW -execute stmt_table using @val; -eval $check; -set @val=404; -set @expected = @expected + 1; ---error ER_WRONG_VALUE_COUNT_ON_ROW -execute stmt_table using @val; -eval $check; - -alter table t7_dependent_table drop column comments; - -set @val=405; -set @expected = @expected + 1; -execute stmt_table using @val; -eval $check; -set @val=406; -execute stmt_table using @val; -eval $check; - - -prepare stmt_table_trigger from 'insert into t7_table(a) value (?)'; -set @val=501; -execute stmt_table_trigger using @val; -eval $check; -set @val=502; -execute stmt_table_trigger using @val; -eval $check; - -drop trigger t7_table_trigger_bi; - -create trigger t7_table_trigger_bi before insert on t7_dependent_table - for each row set NEW.reason="trigger v2"; - -set @val=503; -set @expected = @expected + 1; -execute stmt_table_trigger using @val; -eval $check; -set @val=504; -execute stmt_table_trigger using @val; -eval $check; - -select * from t7_audit order by new_a; - -select * from t7_dependent_table order by new_a; - -drop table t7_proc; -drop table t7_func; -drop table t7_view; -drop table t7_table; -drop table t7_dependent_table; -drop table t7_table_trigger; -drop table t7_audit; -drop procedure audit_proc; -drop function audit_func; -drop view audit_view; +--echo # Test 7-c: dependent VIEW has changed +--echo # +--echo # Note, this scenario is not functioning correctly, see +--echo # Bug#33255 Trigger using views and view ddl : corrupted triggers +--echo # and Bug #33000 Triggers do not detect changes in meta-data. +--echo # +drop trigger t1_ai; +create table t2 (a int unique); +create table t3 (a int unique); +create view v1 as select a from t2; +create trigger t1_ai after insert on t1 for each row + insert into v1 (a) values (new.a); + +--echo # Demonstrate that the same bug is present +--echo # without prepared statements +insert into t1 (a) values (5); +select * from t2; +select * from t3; +drop view v1; +create view v1 as select a from t3; +--error ER_NO_SUCH_TABLE +insert into t1 (a) values (6); +flush table t1; +insert into t1 (a) values (6); +select * from t2; +select * from t3; + +prepare stmt from "insert into t1 (a) values (?)"; +set @var=7; +execute stmt using @var; +call p_verify_reprepare_count(0); +select * from t3; +select * from t2; +drop view v1; +create view v1 as select a from t2; +set @var=8; +execute stmt using @var; +call p_verify_reprepare_count(0); +--echo # +--echo # Sic: the insert went into t3, even though the view now +--echo # points at t2. This is because neither the merged view +--echo # nor its prelocking list are affected by view DDL +--echo # The binary log is of course wrong, since it is not +--echo # using prepared statements +--echo # +select * from t2; +select * from t3; +flush table t1; +set @var=9; +execute stmt using @var; +call p_verify_reprepare_count(1); +select * from t2; +select * from t3; +drop view v1; +drop table t1,t2,t3; + +--echo # Test 7-d: dependent TABLE has changed +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row + insert into t2 (a) values (new.a); +create table t2 (a int); + +prepare stmt from "insert into t1 (a) values (?)"; +set @var=1; +execute stmt using @var; +alter table t2 add column comment varchar(255); +set @var=2; +--echo # Since the dependent table is tracked in the prelocked +--echo # list of the prepared statement, invalidation happens +--echo # and the statement is re-prepared. This is an unnecessary +--echo # side effect, since the statement that *is* dependent +--echo # on t2 definition is inside the trigger, and it is currently +--echo # not reprepared (see the previous test case). +execute stmt using @var; +call p_verify_reprepare_count(1); +select * from t1; +select * from t2; +drop table t1,t2; + +--echo # Test 7-e: dependent TABLE TRIGGER has changed +create table t1 (a int); +create trigger t1_ai after insert on t1 for each row + insert into t2 (a) values (new.a); +create table t2 (a int unique); +create trigger t2_ai after insert on t2 for each row + insert into t3 (a) values (new.a); +create table t3 (a int unique); +create table t4 (a int unique); + +insert into t1 (a) values (1); +select * from t1 join t2 on (t1.a=t2.a) join t3 on (t2.a=t3.a); +drop trigger t2_ai; +create trigger t2_ai after insert on t2 for each row + insert into t4 (a) values (new.a); +insert into t1 (a) values (2); +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); + +prepare stmt from "insert into t1 (a) values (?)"; +set @var=3; +execute stmt using @var; +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); +drop trigger t2_ai; +create trigger t2_ai after insert on t2 for each row + insert into t3 (a) values (new.a); +set @var=4; +execute stmt using @var; +call p_verify_reprepare_count(1); +select * from t1 join t2 on (t1.a=t2.a) join t3 on (t2.a=t3.a); +select * from t1 join t2 on (t1.a=t2.a) join t4 on (t2.a=t4.a); + +drop table t1, t2, t3, t4; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 8: TABLE -> TEMPORARY TABLE transitions +--echo Part 8: TABLE -> TEMPORARY TABLE transitions --echo ===================================================================== ---disable_warnings -drop table if exists t8; ---enable_warnings +--echo # Test 8-a: base table used recreated as temporary table +create table t1 (a int); -create table t8(a int); +prepare stmt from "select * from t1"; +execute stmt; + +drop table t1; +create temporary table t1 (a int); -prepare stmt from 'select * from t8'; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +drop table t1; +deallocate prepare stmt; -drop table t8; -create temporary table t8(a int); +--echo # Test 8-b: temporary table has precedence over base table with same name +create table t1 (a int); +prepare stmt from 'select count(*) from t1'; +execute stmt; +call p_verify_reprepare_count(0); +execute stmt; +call p_verify_reprepare_count(0); -set @expected = @expected + 1; +create temporary table t1 AS SELECT 1; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +deallocate prepare stmt; +drop temporary table t1; +drop table t1; -drop table t8; --echo ===================================================================== ---echo Testing 9: TABLE -> VIEW transitions +--echo Part 9: TABLE -> VIEW transitions --echo ===================================================================== ---disable_warnings -drop table if exists t9; -drop table if exists t9_b; ---enable_warnings - -create table t9(a int); -create table t9_b(a int); +create table t1 (a int); -prepare stmt from 'select * from t9'; +prepare stmt from "select * from t1"; execute stmt; -eval $check; -execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t9; -create view t9 as select * from t9_b; +drop table t1; +create table t2 (a int); +create view t1 as select * from t2; -set @expected = @expected + 1; -execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(1); -drop view t9; -drop table t9_b; +drop view t1; +drop table t2; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 10: TEMPORARY TABLE -> NOTHING transitions +--echo Part 10: TEMPORARY TABLE -> NOTHING transitions --echo ===================================================================== ---disable_warnings -drop temporary table if exists t10; ---enable_warnings +create temporary table t1 (a int); -create temporary table t10(a int); - -prepare stmt from 'select * from t10'; -execute stmt; -eval $check; +prepare stmt from "select * from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop temporary table t10; +drop temporary table t1; --error ER_NO_SUCH_TABLE execute stmt; -eval $check; ---error ER_NO_SUCH_TABLE -execute stmt; -eval $check; +call p_verify_reprepare_count(0); +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 11: TEMPORARY TABLE -> TABLE transitions +--echo Part 11: TEMPORARY TABLE -> TABLE transitions --echo ===================================================================== ---disable_warnings -drop table if exists t11; -drop temporary table if exists t11; ---enable_warnings - -create table t11(a int); -insert into t11(a) value (1); -create temporary table t11(a int); +--echo # Test 11-a: temporary table replaced by base table +create table t1 (a int); +insert into t1 (a) value (1); +create temporary table t1 (a int); -prepare stmt from 'select * from t11'; +prepare stmt from "select * from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +drop temporary table t1; + execute stmt; -eval $check; +call p_verify_reprepare_count(1); + +select * from t1; +drop table t1; +deallocate prepare stmt; -drop temporary table t11; -set @expected = @expected + 1; +--echo # Test 11-b: temporary table has precedence over base table with same name +--echo # temporary table disappears +create table t1 (a int); +create temporary table t1 as select 1 as a; +prepare stmt from "select count(*) from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +drop temporary table t1; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); + +deallocate prepare stmt; +drop table t1; -select * from t11; -drop table t11; --echo ===================================================================== ---echo Testing 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions +--echo Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions --echo ===================================================================== ---disable_warnings -drop temporary table if exists t12; ---enable_warnings - -create temporary table t12(a int); +create temporary table t1 (a int); -prepare stmt from 'select a from t12'; -execute stmt; -eval $check; +prepare stmt from "select a from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop temporary table t12; -create temporary table t12(a int, b int); +drop temporary table t1; +create temporary table t1 (a int, b int); -set @expected = @expected + 1; execute stmt; -eval $check; -execute stmt; -eval $check; +call p_verify_reprepare_count(1); -select * from t12; -drop table t12; +select * from t1; +drop temporary table t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 13: TEMPORARY TABLE -> VIEW transitions +--echo Part 13: TEMPORARY TABLE -> VIEW transitions --echo ===================================================================== ---disable_warnings -drop temporary table if exists t13; -drop table if exists t13_b; ---enable_warnings - -create temporary table t13(a int); -create table t13_b(a int); +create temporary table t1 (a int); +create table t2 (a int); -prepare stmt from 'select * from t13'; +prepare stmt from "select * from t1"; execute stmt; -eval $check; -execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop temporary table t13; -create view t13 as select * from t13_b; +drop temporary table t1; +create view t1 as select * from t2; -set @expected = @expected + 1; -execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(1); -drop view t13; -drop table t13_b; +drop view t1; +drop table t2; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 14: VIEW -> NOTHING transitions +--echo Part 14: VIEW -> NOTHING transitions --echo ===================================================================== ---disable_warnings -drop view if exists t14; -drop table if exists t14_b; ---enable_warnings +create table t2 (a int); +create view t1 as select * from t2; -create table t14_b(a int); -create view t14 as select * from t14_b; - -prepare stmt from 'select * from t14'; -execute stmt; -eval $check; +prepare stmt from "select * from t1"; execute stmt; -eval $check; +drop view t1; -drop view t14; - -set @expected = @expected + 1; --error ER_NO_SUCH_TABLE execute stmt; -eval $check; -set @expected = @expected + 1; +call p_verify_reprepare_count(0); --error ER_NO_SUCH_TABLE execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t14_b; +drop table t2; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 15: VIEW -> TABLE transitions +--echo Part 15: VIEW -> TABLE transitions --echo ===================================================================== ---disable_warnings -drop view if exists t15; -drop table if exists t15_b; ---enable_warnings - -create table t15_b(a int); -create view t15 as select * from t15_b; +create table t2 (a int); +create view t1 as select * from t2; -prepare stmt from 'select * from t15'; +prepare stmt from "select * from t1"; execute stmt; -eval $check; -execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop view t15; -create table t15(a int); +drop view t1; +create table t1 (a int); -set @expected = @expected + 1; -execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(1); -drop table t15_b; -drop table t15; +drop table t2; +drop table t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 16: VIEW -> TEMPORARY TABLE transitions +--echo Part 16: VIEW -> TEMPORARY TABLE transitions --echo ===================================================================== ---disable_warnings -drop view if exists t16; -drop table if exists t16_b; ---enable_warnings - -create table t16_b(a int); -create view t16 as select * from t16_b; +create table t2 (a int); +insert into t2 (a) values (1); +create view t1 as select * from t2; -prepare stmt from 'select * from t16'; -execute stmt; -eval $check; +prepare stmt from "select * from t1"; execute stmt; -eval $check; - -drop view t16; -create temporary table t16(a int); +call p_verify_reprepare_count(0); -set @expected = @expected + 1; +create temporary table t1 (a int); execute stmt; -eval $check; +call p_verify_reprepare_count(1); +drop view t1; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t16_b; -drop temporary table t16; +drop table t2; +drop temporary table t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 17: VIEW -> VIEW (DDL) transitions +--echo Part 17: VIEW -> VIEW (DDL) transitions --echo ===================================================================== ---disable_warnings -drop view if exists t17; -drop table if exists t17_b; ---enable_warnings - -create table t17_b(a int); -insert into t17_b values (10), (20), (30); +create table t2 (a int); +insert into t2 values (10), (20), (30); -create view t17 as select a, 2*a as b, 3*a as c from t17_b; -select * from t17; +create view t1 as select a, 2*a as b, 3*a as c from t2; +select * from t1; -prepare stmt from 'select * from t17'; -execute stmt; -eval $check; +prepare stmt from "select * from t1"; execute stmt; -eval $check; -drop view t17; -create view t17 as select a, 2*a as b, 5*a as c from t17_b; -select * from t17; +drop view t1; +create view t1 as select a, 2*a as b, 5*a as c from t2; +select * from t1; -set @expected = @expected + 1; +--echo # Currently a different result from conventional statements. +--echo # A view is inlined once at prepare, later on view DDL +--echo # does not affect prepared statement and it is not re-prepared. +--echo # This is reported in Bug#36002 Prepared statements: if a view +--echo # used in a statement is replaced, bad data execute stmt; -eval $check; +call p_verify_reprepare_count(0); +flush table t2; execute stmt; -eval $check; +call p_verify_reprepare_count(1); -drop table t17_b; -drop view t17; +drop table t2; +drop view t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 18: VIEW -> VIEW (VIEW dependencies) transitions +--echo Part 18: VIEW -> VIEW (VIEW dependencies) transitions --echo ===================================================================== -# -# Test 18-a: dependent PROCEDURE has changed (via a trigger) -# Test 18-b: dependent FUNCTION has changed -# Test 18-c: dependent VIEW has changed -# Test 18-d: dependent TABLE has changed -# Test 18-e: dependent TABLE TRIGGER has changed -# - ---disable_warnings -drop table if exists t18; -drop table if exists t18_dependent_table; -drop view if exists t18_func; -drop view if exists t18_view; -drop view if exists t18_table; -drop function if exists view_func; -drop view if exists view_view; ---enable_warnings - -# TODO: insertable view -> trigger -# TODO: insertable view -> trigger -> proc ? - -create table t18(a int); -insert into t18 values (1), (2), (3); - -create function view_func(x int) returns int - return x+1; - -create view view_view as select "view v1" as reason from dual; - -create table t18_dependent_table(a int); - -create view t18_func as select a, view_func(a) as b from t18; -create view t18_view as select a, reason as b from t18, view_view; -create view t18_table as select * from t18; +--echo # Part 18a: dependent function has changed +create table t1 (a int); +insert into t1 (a) values (1), (2), (3); +create function f1() returns int return (select max(a) from t1); +create view v1 as select f1(); +prepare stmt from "select * from v1"; +execute stmt; +execute stmt; +call p_verify_reprepare_count(0); +drop function f1; +create function f1() returns int return 2; +--echo # XXX: Bug#12093. We only get a different error +--echo # message because the non-existing procedure error is masked +--echo # by the view. +--error ER_VIEW_INVALID +execute stmt; +--error ER_VIEW_INVALID +execute stmt; +call p_verify_reprepare_count(0); -prepare stmt_func from 'select * from t18_func'; -execute stmt_func; -eval $check; -execute stmt_func; -eval $check; +--echo # Part 18b: dependent procedure has changed (referred to via a function) -drop function view_func; -create function view_func(x int) returns int - return x*x; +create table t2 (a int); +insert into t2 (a) values (4), (5), (6); -set @expected = @expected + 1; -execute stmt_func; -eval $check; -execute stmt_func; -eval $check; +drop function f1; +delimiter |; +create function f1() returns int +begin + declare x int; + call p1(x); + return x; +end| +delimiter ;| +create procedure p1(out x int) select max(a) from t1 into x; -prepare stmt_view from 'select * from t18_view'; -execute stmt_view; -eval $check; -execute stmt_view; -eval $check; +prepare stmt from "select * from v1"; +execute stmt; +execute stmt; +call p_verify_reprepare_count(0); +drop procedure p1; +create procedure p1(out x int) select max(a) from t2 into x; +--echo # XXX: bug. The prelocked list is not invalidated +--echo # and we keep opening table t1, whereas the procedure +--echo # is now referring to table t2 +--error ER_VIEW_INVALID +execute stmt; +call p_verify_reprepare_count(0); +flush table t1; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; -drop view view_view; -create view view_view as select "view v2" as reason from dual; +--echo # Test 18-c: dependent VIEW has changed -set @expected = @expected + 1; -execute stmt_view; -eval $check; -execute stmt_view; -eval $check; +drop view v1; +create view v2 as select a from t1; +create view v1 as select * from v2; +prepare stmt from "select * from v1"; +execute stmt; +execute stmt; +call p_verify_reprepare_count(0); +drop view v2; +create view v2 as select a from t2; +execute stmt; +execute stmt; +call p_verify_reprepare_count(0); +flush table t1; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +--echo # Test 18-d: dependent TABLE has changed +drop view v2; +create table v2 as select * from t1; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +drop table v2; +create table v2 (a int unique) as select * from t2; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); -prepare stmt_table from 'select * from t18_table'; -execute stmt_table; -eval $check; -execute stmt_table; -eval $check; +--echo # Test 18-e: dependent TABLE trigger has changed -alter table t18 add column comments varchar(50) default NULL; +prepare stmt from "insert into v1 (a) values (?)"; +set @var= 7; +execute stmt using @var; +call p_verify_reprepare_count(0); +create trigger v2_bi before insert on v2 for each row set @message="v2_bi"; +set @var=8; +execute stmt using @var; +call p_verify_reprepare_count(1); +select @message; +drop trigger v2_bi; +set @message=null; +set @var=9; +execute stmt using @var; +call p_verify_reprepare_count(1); +select @message; +create trigger v2_bi after insert on v2 for each row set @message="v2_ai"; +set @var= 10; +execute stmt using @var; +call p_verify_reprepare_count(1); +select @message; +select * from v1; -set @expected = @expected + 1; -execute stmt_table; -eval $check; -execute stmt_table; -eval $check; +--echo # Cleanup -drop table t18; -drop table t18_dependent_table; -drop view t18_func; -drop view t18_view; -drop view t18_table; -drop function view_func; -drop view view_view; +--disable_warnings +drop table if exists t1, t2, v1, v2; +drop view if exists v1, v2; +drop function f1; +drop procedure p1; +--enable_warnings +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 19: Special tables (INFORMATION_SCHEMA) +--echo Part 19: Special tables (INFORMATION_SCHEMA) --echo ===================================================================== ---disable_warnings -drop procedure if exists proc_19; ---enable_warnings - # Using a temporary table internally should not confuse the prepared # statement code, and should not raise ER_PS_INVALIDATED errors prepare stmt from - 'select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE + "select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE from INFORMATION_SCHEMA.ROUTINES where - routine_name=\'proc_19\''; + routine_name='p1'"; -create procedure proc_19() select "hi there"; +create procedure p1() select "hi there"; execute stmt; -eval $check; execute stmt; -eval $check; -drop procedure proc_19; -create procedure proc_19() select "hi there, again"; +drop procedure p1; +create procedure p1() select "hi there, again"; execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop procedure proc_19; +drop procedure p1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 20: Special tables (log tables) +--echo Part 20: Special tables (log tables) --echo ===================================================================== prepare stmt from - 'select * from mysql.general_log where argument=\'IMPOSSIBLE QUERY STRING\''; + "select * from mysql.general_log where argument='IMPOSSIBLE QUERY STRING'"; +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log +call p_verify_reprepare_count(0); +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 21: Special tables (system tables) +--echo Part 21: Special tables (system tables) --echo ===================================================================== ---disable_warnings -drop procedure if exists proc_21; ---enable_warnings - prepare stmt from - 'select type, db, name from mysql.proc where name=\'proc_21\''; + "select type, db, name from mysql.proc where name='p1'"; -create procedure proc_21() select "hi there"; +create procedure p1() select "hi there"; execute stmt; -eval $check; execute stmt; -eval $check; -drop procedure proc_21; -create procedure proc_21() select "hi there, again"; +drop procedure p1; +create procedure p1() select "hi there, again"; execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop procedure proc_21; +drop procedure p1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 22: Special tables (views temp tables) +--echo Part 22: Special tables (views temp tables) --echo ===================================================================== ---disable_warnings -drop table if exists t22_b; -drop view if exists t22; ---enable_warnings +create table t1 (a int); -create table t22_b(a int); +create algorithm=temptable view v1 as select a*a as a2 from t1; -create algorithm=temptable view t22 as select a*a as a2 from t22_b; +--echo # Using a temporary table internally should not confuse the prepared +--echo # statement code, and should not raise ER_PS_INVALIDATED errors +show create view v1; -# Using a temporary table internally should not confuse the prepared -# statement code, and should not raise ER_PS_INVALIDATED errors -show create view t22; - -prepare stmt from 'select * from t22'; +prepare stmt from "select * from v1"; -insert into t22_b values (1), (2), (3); +insert into t1 values (1), (2), (3); execute stmt; -eval $check; execute stmt; -eval $check; -insert into t22_b values (4), (5), (6); +insert into t1 values (4), (5), (6); execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t22_b; -drop view t22; +drop table t1; +drop view v1; --echo ===================================================================== ---echo Testing 23: Special tables (internal join tables) +--echo Part 23: Special statements --echo ===================================================================== ---disable_warnings -drop table if exists t23_a; -drop table if exists t23_b; ---enable_warnings +--echo # SQLCOM_ALTER_TABLE: -create table t23_a(a int); -create table t23_b(b int); -# Using a temporary table internally should not confuse the prepared -# statement code, and should not raise ER_PS_INVALIDATED errors -prepare stmt from 'select * from t23_a join t23_b'; - -insert into t23_a values (1), (2), (3); -insert into t23_b values (10), (20), (30); -execute stmt; -eval $check; -execute stmt; -eval $check; +create table t1 (a int); -insert into t23_a values (4); -insert into t23_b values (40); +prepare stmt from "alter table t1 add column b int"; execute stmt; -eval $check; -execute stmt; -eval $check; - -drop table t23_a; -drop table t23_b; - ---echo ===================================================================== ---echo Testing 24: Special statements ---echo ===================================================================== -# SQLCOM_ALTER_TABLE: +drop table t1; +create table t1 (a1 int, a2 int); ---disable_warnings -drop table if exists t24_alter; ---enable_warnings - -create table t24_alter(a int); - -prepare stmt from 'alter table t24_alter add column b int'; +--echo # t1 has changed, and it's does not lead to reprepare execute stmt; -eval $check; - -drop table t24_alter; -create table t24_alter(a1 int, a2 int); -# t24_alter has changed, and it's not a problem +alter table t1 drop column b; execute stmt; -eval $check; -alter table t24_alter drop column b; +alter table t1 drop column b; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t24_alter drop column b; -execute stmt; -eval $check; +drop table t1; -drop table t24_alter; +--echo # SQLCOM_REPAIR: -# SQLCOM_REPAIR: +create table t1 (a int); ---disable_warnings -drop table if exists t24_repair; ---enable_warnings +insert into t1 values (1), (2), (3); -create table t24_repair(a int); -insert into t24_repair values (1), (2), (3); +prepare stmt from "repair table t1"; -prepare stmt from 'repair table t24_repair'; execute stmt; -eval $check; +execute stmt; -drop table t24_repair; -create table t24_repair(a1 int, a2 int); -insert into t24_repair values (1, 10), (2, 20), (3, 30); +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); -# t24_repair has changed, and it's not a problem +--echo # t1 has changed, and it's does not lead to reprepare execute stmt; -eval $check; -alter table t24_repair add column b varchar(50) default NULL; +alter table t1 add column b varchar(50) default NULL; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t24_repair drop column b; +alter table t1 drop column b; execute stmt; -eval $check; - -drop table t24_repair; +call p_verify_reprepare_count(0); -# SQLCOM_ANALYZE: +--echo # SQLCOM_ANALYZE: ---disable_warnings -drop table if exists t24_analyze; ---enable_warnings - -create table t24_analyze(a int); -insert into t24_analyze values (1), (2), (3); - -prepare stmt from 'analyze table t24_analyze'; +prepare stmt from "analyze table t1"; execute stmt; -eval $check; - -drop table t24_analyze; -create table t24_analyze(a1 int, a2 int); -insert into t24_analyze values (1, 10), (2, 20), (3, 30); -# t24_analyze has changed, and it's not a problem +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); +--echo # t1 has changed, and it's not a problem execute stmt; -eval $check; -alter table t24_analyze add column b varchar(50) default NULL; +alter table t1 add column b varchar(50) default NULL; execute stmt; -eval $check; -alter table t24_analyze drop column b; +alter table t1 drop column b; execute stmt; -eval $check; -drop table t24_analyze; +call p_verify_reprepare_count(0); -# SQLCOM_OPTIMIZE: +--echo # SQLCOM_OPTIMIZE: ---disable_warnings -drop table if exists t24_optimize; ---enable_warnings - -create table t24_optimize(a int); -insert into t24_optimize values (1), (2), (3); - -prepare stmt from 'optimize table t24_optimize'; +prepare stmt from "optimize table t1"; execute stmt; -eval $check; -drop table t24_optimize; -create table t24_optimize(a1 int, a2 int); -insert into t24_optimize values (1, 10), (2, 20), (3, 30); +drop table t1; +create table t1 (a1 int, a2 int); +insert into t1 values (1, 10), (2, 20), (3, 30); -# t24_optimize has changed, and it's not a problem +--echo # t1 has changed, and it's not a problem execute stmt; -eval $check; -alter table t24_optimize add column b varchar(50) default NULL; +alter table t1 add column b varchar(50) default NULL; execute stmt; -eval $check; -alter table t24_optimize drop column b; +alter table t1 drop column b; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t24_optimize; +drop table t1; -# SQLCOM_SHOW_CREATE_PROC: +--echo # SQLCOM_SHOW_CREATE_PROC: ---disable_warnings -drop procedure if exists changing_proc; ---enable_warnings - -prepare stmt from 'show create procedure changing_proc'; +prepare stmt from "show create procedure p1"; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; -create procedure changing_proc() begin end; +create procedure p1() begin end; -# changing_proc has changed, and it's not a problem +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log -drop procedure changing_proc; -create procedure changing_proc(x int, y int) begin end; +drop procedure p1; +create procedure p1(x int, y int) begin end; +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log -drop procedure changing_proc; +drop procedure p1; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; - -# SQLCOM_SHOW_CREATE_FUNC: +call p_verify_reprepare_count(0); ---disable_warnings -drop function if exists changing_func; ---enable_warnings +--echo # SQLCOM_SHOW_CREATE_FUNC: -prepare stmt from 'show create function changing_func'; +prepare stmt from "show create function f1"; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; -create function changing_func() returns int return 0; +create function f1() returns int return 0; -# changing_proc has changed, and it's not a problem +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log -drop function changing_func; -create function changing_func(x int, y int) returns int return x+y; +drop function f1; +create function f1(x int, y int) returns int return x+y; +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log -drop function changing_func; +drop function f1; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; +call p_verify_reprepare_count(0); -# SQLCOM_SHOW_CREATE_TRIGGER: +--echo # SQLCOM_SHOW_CREATE_TRIGGER: ---disable_warnings -drop table if exists t24_trigger; ---enable_warnings - -create table t24_trigger(a int); +create table t1 (a int); -prepare stmt from 'show create trigger t24_bi;'; +prepare stmt from "show create trigger t1_bi"; --error ER_TRG_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_TRG_DOES_NOT_EXIST execute stmt; -eval $check; -delimiter $$; -create trigger t24_bi before insert on t24_trigger for each row - begin - set @message= "t24_bi"; - end -$$ -delimiter ;$$ +create trigger t1_bi before insert on t1 for each row set @message= "t1_bi"; -# t24_bi has changed, and it's not a problem +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log + +drop trigger t1_bi; -drop trigger t24_bi; -delimiter $$; -create trigger t24_bi before insert on t24_trigger for each row - begin - set @message= "t24_bi (2)"; - end -$$ -delimiter ;$$ +create trigger t1_bi before insert on t1 for each row set @message= "t1_bi (2)"; -# t24_bi has changed, and it's not a problem -set @expected = @expected + 1; +--disable_result_log execute stmt; -eval $check; execute stmt; -eval $check; +--enable_result_log -drop trigger t24_bi; +drop trigger t1_bi; --error ER_TRG_DOES_NOT_EXIST execute stmt; -eval $check; --error ER_TRG_DOES_NOT_EXIST execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t24_trigger; +drop table t1; +deallocate prepare stmt; --echo ===================================================================== ---echo Testing 25: Testing the strength of TABLE_SHARE version +--echo Part 24: Testing the strength of TABLE_SHARE version --echo ===================================================================== -# Test 25-a: number of columns +--echo # Test 24-a: number of columns ---disable_warnings -drop table if exists t25_num_col; ---enable_warnings - -create table t25_num_col(a int); +create table t1 (a int); -prepare stmt from 'select a from t25_num_col'; -execute stmt; -eval $check; +prepare stmt from "select a from t1"; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t25_num_col add column b varchar(50) default NULL; +alter table t1 add column b varchar(50) default NULL; -set @expected = @expected + 1; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t25_num_col; +--echo # Test 24-b: column name -# Test 25-b: column name +alter table t1 change b c int; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); ---disable_warnings -drop table if exists t25_col_name; ---enable_warnings +--echo # Test 24-c: column type -create table t25_col_name(a int); +alter table t1 change a a varchar(10); -prepare stmt from 'select * from t25_col_name'; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +--echo # Test 24-d: column type length -alter table t25_col_name change a b int; +alter table t1 change a a varchar(20); -set @expected = @expected + 1; ---error ER_PS_REBIND execute stmt; -eval $check; -set @expected = @expected + 1; ---error ER_PS_REBIND +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t25_col_name; +--echo # Test 24-e: column NULL property -# Test 25-c: column type +alter table t1 change a a varchar(20) NOT NULL; ---disable_warnings -drop table if exists t25_col_type; ---enable_warnings - -create table t25_col_type(a int); - -prepare stmt from 'select * from t25_col_type'; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); + +--echo # Test 24-f: column DEFAULT -alter table t25_col_type change a a varchar(10); +alter table t1 change c c int DEFAULT 20; -set @expected = @expected + 1; ---error ER_PS_REBIND execute stmt; -eval $check; -set @expected = @expected + 1; ---error ER_PS_REBIND +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -drop table t25_col_type; +--echo # Test 24-g: number of keys +create unique index t1_a_idx on t1 (a); -# Test 25-d: column type length +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); ---disable_warnings -drop table if exists t25_col_type_length; ---enable_warnings +--echo # Test 24-h: changing index uniqueness -create table t25_col_type_length(a varchar(10)); +drop index t1_a_idx on t1; +create index t1_a_idx on t1 (a); -prepare stmt from 'select * from t25_col_type_length'; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t25_col_type_length change a a varchar(20); +--echo # Cleanup +drop table t1; -set @expected = @expected + 1; ---error ER_PS_REBIND -execute stmt; -eval $check; -set @expected = @expected + 1; ---error ER_PS_REBIND -execute stmt; -eval $check; +deallocate prepare stmt; -drop table t25_col_type_length; +--echo ===================================================================== +--echo Testing reported bugs +--echo ===================================================================== -# Test 25-e: column NULL property +--echo # +--echo # Bug#27420 A combination of PS and view operations cause +--echo # error + assertion on shutdown +--echo # --disable_warnings -drop table if exists t25_col_null; +drop table if exists t_27420_100; +drop table if exists t_27420_101; +drop view if exists v_27420; --enable_warnings -create table t25_col_null(a varchar(10)); +create table t_27420_100(a int); +insert into t_27420_100 values (1), (2); + +create table t_27420_101(a int); +insert into t_27420_101 values (1), (2); + +create view v_27420 as select t_27420_100.a X, t_27420_101.a Y + from t_27420_100, t_27420_101 + where t_27420_100.a=t_27420_101.a; + +prepare stmt from "select * from v_27420"; -prepare stmt from 'select * from t25_col_null'; -execute stmt; -eval $check; execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t25_col_null change a a varchar(10) NOT NULL; +drop view v_27420; +create table v_27420(X int, Y int); -set @expected = @expected + 1; ---error ER_PS_REBIND execute stmt; -eval $check; -set @expected = @expected + 1; ---error ER_PS_REBIND +call p_verify_reprepare_count(1); + +drop table v_27420; +# passes in 5.0, fails in 5.1, should pass +create table v_27420 (a int, b int, filler char(200)); + execute stmt; -eval $check; +call p_verify_reprepare_count(1); -drop table t25_col_null; +drop table t_27420_100; +drop table t_27420_101; +drop table v_27420; +deallocate prepare stmt; -# Test 25-f: column DEFAULT +--echo # +--echo # Bug#27430 Crash in subquery code when in PS and table DDL changed +--echo # after PREPARE +--echo # --disable_warnings -drop table if exists t25_col_default; +drop table if exists t_27430_1; +drop table if exists t_27430_2; --enable_warnings -create table t25_col_default(a int, b int DEFAULT 10); +create table t_27430_1 (a int not null, oref int not null, key(a)); +insert into t_27430_1 values + (1, 1), + (1, 1234), + (2, 3), + (2, 1234), + (3, 1234); -prepare stmt from 'insert into t25_col_default(a) values (?)'; -set @val=1; -execute stmt using @val; -eval $check; -set @val=2; -execute stmt using @val; -eval $check; +create table t_27430_2 (a int not null, oref int not null); +insert into t_27430_2 values + (1, 1), + (2, 2), + (1234, 3), + (1234, 4); -alter table t25_col_default change b b int DEFAULT 20; +prepare stmt from + "select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2"; -set @val=3; -# Must insert the correct default value for b -set @expected = @expected + 1; -execute stmt using @val; -eval $check; +execute stmt; +call p_verify_reprepare_count(0); -set @val=4; -# Must insert the correct default value for b -execute stmt using @val; -eval $check; +drop table t_27430_1, t_27430_2; -select * from t25_col_default; +create table t_27430_1 (a int, oref int, key(a)); +insert into t_27430_1 values + (1, 1), + (1, NULL), + (2, 3), + (2, NULL), + (3, NULL); -drop table t25_col_default; +create table t_27430_2 (a int, oref int); +insert into t_27430_2 values + (1, 1), + (2,2), + (NULL, 3), + (NULL, 4); -# Test 25-g: number of keys +execute stmt; +call p_verify_reprepare_count(1); + +drop table t_27430_1; +drop table t_27430_2; +deallocate prepare stmt; + +--echo # +--echo # Bug#27690 Re-execution of prepared statement after table +--echo # was replaced with a view crashes +--echo # --disable_warnings -drop table if exists t25_index; +drop table if exists t_27690_1; +drop view if exists v_27690_1; +drop table if exists v_27690_2; --enable_warnings -create table t25_index(a varchar(10)); +create table t_27690_1 (a int, b int); +insert into t_27690_1 values (1,1),(2,2); -prepare stmt from 'select * from t25_index'; -execute stmt; -eval $check; -execute stmt; -eval $check; +create table v_27690_1 as select * from t_27690_1; +create table v_27690_2 as select * from t_27690_1; -create index i1 on t25_index(a); +prepare stmt from "select * from v_27690_1, v_27690_2"; -set @expected = @expected + 1; execute stmt; -eval $check; execute stmt; -eval $check; - -drop table t25_index; -# Test 25-h: changing index uniqueness +drop table v_27690_1; ---disable_warnings -drop table if exists t25_index_unique; ---enable_warnings +--error ER_NO_SUCH_TABLE +execute stmt; -create table t25_index_unique(a varchar(10), b varchar(10)); -create index i1 on t25_index_unique(a, b); +--error ER_NO_SUCH_TABLE +execute stmt; +call p_verify_reprepare_count(0); -show create table t25_index_unique; +create view v_27690_1 as select A.a, A.b from t_27690_1 A, t_27690_1 B; -prepare stmt from 'select * from t25_index_unique'; execute stmt; -eval $check; +call p_verify_reprepare_count(1); execute stmt; -eval $check; +call p_verify_reprepare_count(0); -alter table t25_index_unique drop index i1; -create unique index i1 on t25_index_unique(a, b); +drop table t_27690_1; +drop view v_27690_1; +drop table v_27690_2; +deallocate prepare stmt; + +--echo #===================================================================== +--echo # TODO: fix the below two bugs and modify their tests +--echo # +--echo # Bug#21294 Executing a prepared statement that executes +--echo # a stored function which was recreat +--echo # -show create table t25_index_unique; +create function f1() returns int return 10; -set @expected = @expected + 1; +prepare stmt from "select f1()"; execute stmt; -eval $check; + +drop function f1; +create function f1() returns int return 10; + +# might pass or fail, implementation dependent +--error ER_SP_DOES_NOT_EXIST execute stmt; -eval $check; -drop table t25_index_unique; +drop function f1; +create function f1() returns int return 20; ---echo ===================================================================== ---echo Testing reported bugs ---echo ===================================================================== +--error ER_SP_DOES_NOT_EXIST +execute stmt; +call p_verify_reprepare_count(0); -# -# Bug#12093 (SP not found on second PS execution if another thread drops -# other SP in between) -# +drop function f1; +deallocate prepare stmt; +--echo # +--echo # Bug#12093 SP not found on second PS execution if another thread drops +--echo # other SP in between +--echo # --disable_warnings -drop table if exists table_12093; -drop function if exists func_12093; -drop function if exists func_12093_unrelated; -drop procedure if exists proc_12093; +drop table if exists t_12093; +drop function if exists f_12093; +drop function if exists f_12093_unrelated; +drop procedure if exists p_12093; --enable_warnings -connect (con1,localhost,root,,); +create table t_12093 (a int); -connection default; +create function f_12093() returns int return (select count(*) from t_12093); -create table table_12093(a int); +create procedure p_12093(a int) select * from t_12093; -delimiter //; +create function f_12093_unrelated() returns int return 2; +create procedure p_12093_unrelated() begin end; -create function func_12093() -returns int -begin - return (select count(*) from table_12093); -end// - -create procedure proc_12093(a int) -begin - select * from table_12093; -end// - -delimiter ;// - -create function func_12093_unrelated() returns int return 2; -create procedure proc_12093_unrelated() begin end; - -prepare stmt_sf from 'select func_12093();'; -prepare stmt_sp from 'call proc_12093(func_12093())'; +prepare stmt_sf from 'select f_12093();'; +prepare stmt_sp from 'call p_12093(f_12093())'; execute stmt_sf; -eval $check; execute stmt_sp; -eval $check; +connect (con1,localhost,root,,); connection con1; -drop function func_12093_unrelated; -drop procedure proc_12093_unrelated; +drop function f_12093_unrelated; +drop procedure p_12093_unrelated; connection default; -# previously, failed with --error 1305 +--echo # XXX: bug +--error ER_SP_DOES_NOT_EXIST execute stmt_sf; -eval $check; -# previously, failed with --error 1305 +--echo # XXX: bug +--error ER_SP_DOES_NOT_EXIST execute stmt_sp; -eval $check; -# previously, failed with --error 1305 +--echo # XXX: bug +--error ER_SP_DOES_NOT_EXIST execute stmt_sf; -eval $check; -# previously, failed with --error 1305 +--echo # XXX: bug +--error ER_SP_DOES_NOT_EXIST execute stmt_sp; -eval $check; +call p_verify_reprepare_count(0); + +disconnect con1; +drop table t_12093; +drop function f_12093; +drop procedure p_12093; deallocate prepare stmt_sf; deallocate prepare stmt_sp; -disconnect con1; -drop table table_12093; -drop function func_12093; -drop procedure proc_12093; +--echo ===================================================================== +--echo Ensure that metadata validation is performed for every type of +--echo SQL statement where it is needed. +--echo ===================================================================== -# -# Bug#21294 (executing a prepared statement that executes a stored function -# which was recreat) -# +--echo # +--echo # SQLCOM_SELECT +--echo # --disable_warnings -drop function if exists func_21294; +drop table if exists t1; --enable_warnings +create table t1 (a int); +prepare stmt from "select 1 as res from dual where (1) in (select * from t1)"; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; +call p_verify_reprepare_count(1); -create function func_21294() returns int return 10; +--echo # +--echo # SQLCOM_CREATE_TABLE +--echo # -prepare stmt from "select func_21294()"; +--disable_warnings +drop table if exists t1; +drop table if exists t2; +--enable_warnings +create table t1 (a int); +prepare stmt from 'create table t2 as select * from t1'; +execute stmt; +drop table t2; +execute stmt; +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +# Base table with name of table to be created exists +--error ER_TABLE_EXISTS_ERROR +execute stmt; +call p_verify_reprepare_count(1); +--error ER_TABLE_EXISTS_ERROR +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +# Temporary table with name of table to be created exists +create temporary table t2 (a int); +--error ER_TABLE_EXISTS_ERROR +execute stmt; +call p_verify_reprepare_count(1); +--error ER_TABLE_EXISTS_ERROR +execute stmt; +call p_verify_reprepare_count(0); +drop temporary table t2; +execute stmt; +call p_verify_reprepare_count(1); +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +# View with name of table to be created exists +# Attention: +# We cannot print the error message because it contains a random filename. +# Example: 1050: Table '<some_path>/var/tmp/#sql_6979_0' already exists +# Therefore we mangle it via +# "--error ER_TABLE_EXISTS_ERROR,9999" (9999 is currently not used) +# to "Got one of the listed errors". +create view t2 as select 1; +--error ER_TABLE_EXISTS_ERROR,9999 +execute stmt; +call p_verify_reprepare_count(1); +--error ER_TABLE_EXISTS_ERROR,9999 +execute stmt; +call p_verify_reprepare_count(0); +drop view t2; +drop table t1; +# Table to be used recreated (drop,create) with different layout +create table t1 (x varchar(20)); +execute stmt; +call p_verify_reprepare_count(1); +select * from t2; +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +# Table to be used has a modified (alter table) layout +alter table t1 add column y decimal(10,3); +execute stmt; +call p_verify_reprepare_count(1); +select * from t2; +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t1; +deallocate prepare stmt; +--echo # XXX: no validation of the first table in case of +--echo # CREATE TEMPORARY TABLE. This is a shortcoming of the current code, +--echo # but since validation is not strictly necessary, nothing is done +--echo # about it. +--echo # Will be fixed as part of work on Bug#21431 "Incomplete support of +--echo # temporary tables" +create table t1 (a int); +insert into t1 (a) values (1); +prepare stmt from "create temporary table if not exists t2 as select * from t1"; +execute stmt; +drop table t2; +execute stmt; +execute stmt; +select * from t2; execute stmt; -eval $check; +select * from t2; +drop table t2; +create temporary table t2 (a varchar(10)); +execute stmt; +select * from t2; +call p_verify_reprepare_count(0); +drop table t1; +create table t1 (x int); +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +drop table t1; +drop temporary table t2; +drop table t2; +deallocate prepare stmt; -drop function func_21294; -create function func_21294() returns int return 10; +create table t1 (a int); +prepare stmt from "create table t2 like t1"; +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +# Table to be used does not exist +drop table t1; +--error ER_NO_SUCH_TABLE +execute stmt; +call p_verify_reprepare_count(0); +--error ER_NO_SUCH_TABLE +execute stmt; +call p_verify_reprepare_count(0); +# Table to be used recreated (drop,create) with different layout +create table t1 (x char(17)); +execute stmt; +call p_verify_reprepare_count(1); +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t2; +# Table to be used has a modified (alter table) layout +alter table t1 add column y time; +execute stmt; +call p_verify_reprepare_count(1); +select * from t2; +drop table t2; +execute stmt; +call p_verify_reprepare_count(0); +drop table t1; +drop table t2; +deallocate prepare stmt; -# might pass or fail, implementation dependent + +--echo # +--echo # SQLCOM_UPDATE +--echo # + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "update t2 set a=a+1 where (1) in (select * from t1)"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; -drop function func_21294; -create function func_21294() returns int return 20; +--echo # +--echo # SQLCOM_INSERT +--echo # -set @expected = @expected + 1; +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "insert into t2 set a=((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); execute stmt; -eval $check; +drop table t1, t2; deallocate prepare stmt; -drop function func_21294; -# -# Bug#27420 (A combination of PS and view operations cause error + assertion -# on shutdown) -# +--echo # +--echo # SQLCOM_INSERT_SELECT +--echo # --disable_warnings -drop table if exists t_27420_100; -drop table if exists t_27420_101; -drop view if exists v_27420; +drop table if exists t1, t2; --enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "insert into t2 select * from t1"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; -connect (con1,localhost,root,,); +--echo # +--echo # SQLCOM_REPLACE +--echo # -connection default; +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "replace t2 set a=((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; -create table t_27420_100(a int); -insert into t_27420_100 values (1), (2); +--echo # +--echo # SQLCOM_REPLACE_SELECT +--echo # -create table t_27420_101(a int); -insert into t_27420_101 values (1), (2); +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "replace t2 select * from t1"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; -create view v_27420 as select t_27420_100.a X, t_27420_101.a Y - from t_27420_100, t_27420_101 - where t_27420_100.a=t_27420_101.a; +--echo # +--echo # SQLCOM_DELETE +--echo # + +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +prepare stmt from "delete from t2 where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2; +deallocate prepare stmt; -prepare stmt from 'select * from v_27420'; +--echo # +--echo # SQLCOM_DELETE_MULTI +--echo # +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +prepare stmt from "delete t2, t3 from t2, t3 where (1) in (select * from t1)"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2, t3; +deallocate prepare stmt; -connection con1; +--echo # +--echo # SQLCOM_UPDATE_MULTI +--echo # -drop view v_27420; -create table v_27420(X int, Y int); +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +prepare stmt from "update t2, t3 set t3.a=t2.a, t2.a=null where (1) in (select * from t1)"; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1, t2, t3; +deallocate prepare stmt; +--echo # Intermediate results: 8 SQLCOMs tested, 8 automatic reprepares +call p_verify_reprepare_count(8); -connection default; +--echo # +--echo # SQLCOM_LOAD +--echo # + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a varchar(20)); +--error ER_UNSUPPORTED_PS +prepare stmt from "load data infile '../std_data_ln/words.dat' into table t1"; +drop table t1; + +--echo # +--echo # SQLCOM_SHOW_DATABASES +--echo # + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show databases where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -set @expected = @expected + 1; +--echo # +--echo # SQLCOM_SHOW_TABLES +--echo # + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show tables where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); execute stmt; -eval $check; +drop table t1; +deallocate prepare stmt; -connection con1; +--echo # +--echo # SQLCOM_SHOW_FIELDS +--echo # -drop table v_27420; -# passes in 5.0, fails in 5.1, should pass -create table v_27420 (a int, b int, filler char(200)); +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show fields from t1 where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -connection default; +--echo # +--echo # SQLCOM_SHOW_KEYS +--echo # -set @expected = @expected + 1; ---error ER_PS_REBIND +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show keys from t1 where (1) in (select * from t1)"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -disconnect con1; +--echo # +--echo # SQLCOM_SHOW_VARIABLES +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show variables where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; deallocate prepare stmt; -drop table t_27420_100; -drop table t_27420_101; -drop table v_27420; -# -# Bug#27430 (Crash in subquery code when in PS and table DDL changed after -# PREPARE) -# +--echo # +--echo # SQLCOM_SHOW_STATUS +--echo # --disable_warnings -drop table if exists t_27430_1; -drop table if exists t_27430_2; +drop table if exists t1; --enable_warnings +create table t1 (a int); +prepare stmt from "show status where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -create table t_27430_1 (a int not null, oref int not null, key(a)); -insert into t_27430_1 values - (1, 1), - (1, 1234), - (2, 3), - (2, 1234), - (3, 1234); +--echo # +--echo # SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_LOGS, +--echo # SQLCOM_SHOW_ENGINE_MUTEX, SQLCOM_SHOW_PROCESSLIST +--echo # -create table t_27430_2 (a int not null, oref int not null); -insert into t_27430_2 values - (1, 1), - (2, 2), - (1234, 3), - (1234, 4); +--echo # Currently can not have a where clause, need to be covered +--echo # with tests -prepare stmt from - 'select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2'; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +--error ER_PARSE_ERROR +prepare stmt from "show engine all status where (1) in (select * from t1)"; +--error ER_PARSE_ERROR +prepare stmt from "show engine all logs where (1) in (select * from t1)"; +--error ER_PARSE_ERROR +prepare stmt from "show engine all mutex where (1) in (select * from t1)"; +--error ER_PARSE_ERROR +prepare stmt from "show processlist where (1) in (select * from t1)"; +drop table t1; + +--echo # +--echo # SQLCOM_SHOW_CHARSETS +--echo # -execute stmt; -eval $check; -execute stmt; -eval $check; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show charset where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -drop table t_27430_1, t_27430_2; +--echo # +--echo # SQLCOM_SHOW_COLLATIONS +--echo # -create table t_27430_1 (a int, oref int, key(a)); -insert into t_27430_1 values - (1, 1), - (1, NULL), - (2, 3), - (2, NULL), - (3, NULL); +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show collation where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -create table t_27430_2 (a int, oref int); -insert into t_27430_2 values - (1, 1), - (2,2), - (NULL, 3), - (NULL, 4); +--echo # +--echo # SQLCOM_SHOW_TABLE_STATUS +--echo # -set @expected = @expected + 1; ---error ER_PS_REBIND +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show table status where (1) in (select * from t1)"; execute stmt; -eval $check; -set @expected = @expected + 1; ---error ER_PS_REBIND +drop table t1; +create table t1 (x int); execute stmt; -eval $check; +drop table t1; +deallocate prepare stmt; + +--echo # +--echo # SQLCOM_SHOW_TRIGGERS +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show triggers where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; deallocate prepare stmt; -drop table t_27430_1; -drop table t_27430_2; -# -# Bug#27690 (Re-execution of prepared statement after table was replaced -# with a view crashes) -# +--echo # +--echo # SQLCOM_SHOW_OPEN_TABLES +--echo # --disable_warnings -drop table if exists t_27690_1; -drop view if exists v_27690_1; -drop table if exists v_27690_2; +drop table if exists t1; --enable_warnings +create table t1 (a int); +prepare stmt from "show open tables where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -create table t_27690_1 (a int, b int); -insert into t_27690_1 values (1,1),(2,2); +--echo # +--echo # SQLCOM_SHOW_STATUS_PROC +--echo # -create table v_27690_1 as select * from t_27690_1; -create table v_27690_2 as select * from t_27690_1; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show procedure status where (1) in (select * from t1)"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -prepare stmt from 'select * from v_27690_1, v_27690_2'; +--echo # +--echo # SQLCOM_SHOW_STATUS_FUNC +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show function status where (1) in (select * from t1)"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); execute stmt; -eval $check; +drop table t1; +deallocate prepare stmt; -drop table v_27690_1; +--echo # +--echo # SQLCOM_SHOW_EVENTS +--echo # ---error ER_NO_SUCH_TABLE +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "show events where (1) in (select * from t1)"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; ---error ER_NO_SUCH_TABLE +--echo # +--echo # SQLCOM_SET_OPTION +--echo # + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "set @a=((1) in (select * from t1))"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -create view v_27690_1 as select A.a, A.b from t_27690_1 A, t_27690_1 B; +--echo # +--echo # SQLCOM_DO +--echo # + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt from "do ((1) in (select * from t1))"; +execute stmt; +drop table t1; +create table t1 (x int); +execute stmt; +drop table t1; +deallocate prepare stmt; -set @expected = @expected + 1; +--echo # +--echo # SQLCOM_CALL +--echo # + +--disable_warnings +drop table if exists t1; +drop procedure if exists p1; +--enable_warnings +create procedure p1(a int) begin end; +create table t1 (a int); +prepare stmt from "call p1((1) in (select * from t1))"; execute stmt; -eval $check; +drop table t1; +create table t1 (x int); execute stmt; -eval $check; +drop table t1; +drop procedure p1; +deallocate prepare stmt; +--echo # +--echo # SQLCOM_CREATE_VIEW +--echo # + +--disable_warnings +drop table if exists t1; +drop view if exists v1; +--enable_warnings +create table t1 (a int); +prepare stmt from "create view v1 as select * from t1"; +execute stmt; +drop view v1; +drop table t1; +create table t1 (x int); +execute stmt; +drop view v1; +drop table t1; deallocate prepare stmt; -drop table t_27690_1; -drop view v_27690_1; -drop table v_27690_2; +--echo # Intermediate result: number of reprepares matches the number +--echo # of tests +call p_verify_reprepare_count(18); + +--echo # +--echo # SQLCOM_ALTER_VIEW +--echo # +--disable_warnings +drop view if exists v1; +--enable_warnings +create view v1 as select 1; +--error ER_UNSUPPORTED_PS +prepare stmt from "alter view v1 as select 2"; +drop view v1; + +--echo # Cleanup +--echo # +--disable_warnings +drop temporary table if exists t1, t2, t3; +drop table if exists t1, t2, t3, v1, v2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists v1, v2; +--enable_warnings diff --git a/mysql-test/t/ps_ddl1.test b/mysql-test/t/ps_ddl1.test new file mode 100644 index 00000000000..0145d445a14 --- /dev/null +++ b/mysql-test/t/ps_ddl1.test @@ -0,0 +1,398 @@ +# +# Testing the behavior of 'PREPARE', 'DDL', 'EXECUTE' scenarios +# +# There are several subtests which are probably "superfluous" because a DDL +# statement before the EXECUTE <prepared stmt handle> contained a keyword +# or action (Example: Alter) which causes that all prepared statements using +# the modified object are reprepared before execution. +# Please do not delete these subtests if they disturb. Just disable them by +# if (0) +# { +# <tests to disable> +# }. +# There might be future optimisations of the server which decrease the amount +# of unneeded reprepares or skip unneeded prepare steps and than these subtests +# might become valuable. +# Example: +# Every preceding ALTER TABLE seems to cause a reprepare. +# But if the ALTER only changed the table comment ... +# +# Created: 2008-04-18 mleich +# + +--disable_warnings +drop temporary table if exists t1; +drop table if exists t1, t2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists t1; +drop schema if exists mysqltest; +--enable_warnings + +delimiter |; +create procedure p_verify_reprepare_count(expected int) +begin + declare old_reprepare_count int default @reprepare_count; + + select variable_value from + information_schema.session_status where + variable_name='com_stmt_reprepare' + into @reprepare_count; + + if old_reprepare_count + expected <> @reprepare_count then + select concat("Expected: ", expected, + ", actual: ", @reprepare_count - old_reprepare_count) + as "ERROR"; + else + select '' as "SUCCESS"; + end if; +end| +delimiter ;| +set @reprepare_count= 0; +flush status; + +--disable_warnings +drop table if exists t1; +--disable_warnings + +--echo # Column added or dropped is not within the list of selected columns +--echo # or table comment has changed. +--echo # A reprepare is probably not needed. +create table t1 (a int, b int); +prepare stmt from "select a from t1"; +execute stmt; +call p_verify_reprepare_count(0); +alter table t1 add column c int; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +alter table t1 drop column b; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +alter table t1 comment "My best table"; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +drop table t1; +deallocate prepare stmt; + +--echo # Selects using the table at various positions, inser,update ... +--echo # + the table disappears +create table t1 (a int); +# Attention: +# "truncate" must have the first position (= executed as last prepared +# statement), because it recreates the table which has leads to reprepare +# (is this really needed) of all statements. +prepare stmt1 from "truncate t1"; +prepare stmt2 from "select 1 as my_column from t1"; +prepare stmt3 from "select 1 as my_column from (select * from t1) as t2"; +prepare stmt4 from +"select 1 as my_column from (select 1) as t2 where exists (select 1 from t1)"; +prepare stmt5 from "select * from (select 1 as b) as t2, t1"; +prepare stmt6 from "select * from t1 union all select 1.5"; +prepare stmt7 from "select 1 as my_column union all select 1 from t1"; +prepare stmt8 from "insert into t1 values(1),(2)"; +prepare stmt9 from "update t1 set a = 3 where a = 2"; +prepare stmt10 from "delete from t1 where a = 1"; +let ps_stmt_count= 10; +--echo # Attention: Result logging is disabled. +# Checks of correct results of statements are not the goal of this test. +let $num= $ps_stmt_count; +while ($num) +{ + --disable_result_log + eval execute stmt$num; + --enable_result_log + dec $num; +} +# There was no reprepare needed, because none of the objects has changed. +call p_verify_reprepare_count(0); +drop table t1; +let $num= $ps_stmt_count; +while ($num) +{ + --error ER_NO_SUCH_TABLE + eval execute stmt$num; + dec $num; +} +# There was no reprepare needed, because the statement is no more applicable. +call p_verify_reprepare_count(0); +let $num= $ps_stmt_count; +while ($num) +{ + eval deallocate prepare stmt$num; + dec $num; +} + +--echo # Selects using the table at various positions, inser,update ... +--echo # + layout change (drop column) which must cause a reprepare +create table t1 (a int, b int); +insert into t1 values(1,1),(2,2),(3,3); +create table t2 like t1; +insert into t1 values(2,2); +prepare stmt1 from "select a,b from t1"; +prepare stmt2 from "select a,b from (select * from t1) as t1"; +prepare stmt3 from "select * from t1 where a = 2 and b = 2"; +prepare stmt4 from "select * from t2 where (a,b) in (select * from t1)"; +prepare stmt5 from "select * from t1 union select * from t2"; +prepare stmt6 from "select * from t1 union all select * from t2"; +prepare stmt7 from "insert into t1 set a = 4, b = 4"; +prepare stmt8 from "insert into t1 select * from t2"; +let ps_stmt_count= 8; +--echo # Attention: Result logging is disabled. +# Checks of correct results of statements are not the goal of this test. +let $num= $ps_stmt_count; +while ($num) +{ + --disable_result_log + eval execute stmt$num; + --enable_result_log + dec $num; +} +call p_verify_reprepare_count(0); +alter table t1 drop column b; +--disable_abort_on_error +let $num= $ps_stmt_count; +while ($num) +{ + eval execute stmt$num; + # A reprepare is needed, because layout change of t1 affects statement. + call p_verify_reprepare_count(1); + dec $num; +} +let $num= $ps_stmt_count; +while ($num) +{ + eval execute stmt$num; + call p_verify_reprepare_count(1); + dec $num; +} +--echo # Why does the INSERT ... SELECT does not get a reprepare or is +--echo # only the counter not incremented? +eval execute stmt8; +call p_verify_reprepare_count(1); +--enable_abort_on_error +alter table t2 add column c int; +--error ER_WRONG_VALUE_COUNT_ON_ROW +eval execute stmt8; +call p_verify_reprepare_count(1); +let $num= $ps_stmt_count; +while ($num) +{ + eval deallocate prepare stmt$num; + dec $num; +} +drop table t1; +drop table t2; + + +--echo # select AVG(<col>) + optimizer uses index meets loss of the index +create table t1 (a int, b int, primary key(b),unique index t1_unq_idx(a)); +# We need an index which is not converted to PRIMARY KEY (becomes in +# case of InnoDB the key used for table clustering). +insert into t1 set a = 0, b = 0; +insert into t1 select a + 1, b + 1 from t1; +insert into t1 select a + 2, b + 2 from t1; +insert into t1 select a + 4, b + 4 from t1; +insert into t1 select a + 8, b + 8 from t1; +# "using index" optimizer strategy is intended +let $possible_keys= + query_get_value(explain select avg(a) from t1, possible_keys, 1); +let $extra= + query_get_value(explain select avg(a) from t1, Extra, 1); +--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra +prepare stmt from "select avg(a) from t1"; +execute stmt; +call p_verify_reprepare_count(0); +execute stmt; +call p_verify_reprepare_count(0); + +alter table t1 drop index t1_unq_idx; +let $possible_keys= + query_get_value(explain select avg(a) from t1, possible_keys, 1); +let $extra= + query_get_value(explain select avg(a) from t1, Extra, 1); +--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); + + +--echo # select AVG(<col>) + optimizer uses table scan meets a new index +alter table t1 add unique index t1_unq_idx(a); +let $possible_keys= + query_get_value(explain select avg(a) from t1, possible_keys, 1); +let $extra= + query_get_value(explain select avg(a) from t1, Extra, 1); +--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); + +deallocate prepare stmt; +drop table t1; + + +--echo # table replaced by not updatable view - Insert +create table t1 (a int); +prepare stmt from "insert into t1 values(1)"; +execute stmt; +call p_verify_reprepare_count(0); + +drop table t1; +create view t1 as select 1; +--error ER_NON_INSERTABLE_TABLE +execute stmt; +call p_verify_reprepare_count(1); + +drop view t1; +create table t2 (a int); +create view t1 as select * from t2 with check option; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + +deallocate prepare stmt; +drop view t1; +drop table t2; + + +--echo ===================================================================== +--echo Some freestyle tests +--echo ===================================================================== + +create temporary table t1 as select 1 as a; +delimiter |; +create procedure p1() +begin + drop temporary table t1; +end| +create function f1() returns int +begin + call p1(); + return 1; +end| +delimiter ;| + +prepare stmt from "select f1() as my_column, a from t1"; +--error ER_CANT_REOPEN_TABLE +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + +prepare stmt from "select a, f1() as my_column from t1"; +--error ER_CANT_REOPEN_TABLE +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + +prepare stmt from "select f1() as my_column, count(*) from t1"; +--error ER_CANT_REOPEN_TABLE +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + +prepare stmt from "select count(*), f1() as my_column from t1"; +--error ER_CANT_REOPEN_TABLE +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + + +--echo # Execute fails, no drop of temporary table +prepare stmt from "select 1 as my_column from (select 1) as t2 + where exists (select f1() from t1)"; +execute stmt; +call p_verify_reprepare_count(0); +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; + +--echo # Execute drops temporary table +prepare stmt from "select f1()"; +execute stmt; +call p_verify_reprepare_count(0); +--error ER_BAD_TABLE_ERROR +execute stmt; +call p_verify_reprepare_count(0); + +drop function f1; +drop procedure p1; +deallocate prepare stmt; + +--echo # Execute fails, temporary table is not replaced by another +create temporary table t1 as select 1 as a; +delimiter |; +create procedure p1() +begin + drop temporary table t1; + create temporary table t1 as select 'abc' as a; +end| +create function f1() returns int +begin + call p1(); + return 1; +end| +delimiter ;| +prepare stmt from "select count(*), f1() as my_column from t1"; +--error ER_CANT_REOPEN_TABLE +execute stmt; +call p_verify_reprepare_count(0); +select * from t1; +deallocate prepare stmt; + +prepare stmt from "call p1"; +execute stmt; +drop procedure p1; +create schema mysqltest; +delimiter |; +create procedure mysqltest.p1() +begin + drop schema mysqltest; + create schema mysqltest; +end| +delimiter ;| +--error ER_SP_DOES_NOT_EXIST +execute stmt; +call p_verify_reprepare_count(0); +--error ER_SP_DOES_NOT_EXIST +execute stmt; +call p_verify_reprepare_count(0); +deallocate prepare stmt; +drop schema mysqltest; +drop temporary table t1; + + +# Bug#36089 drop temp table in SP called by function, crash +# Note: A non prepared "select 1 from t1 having count(*) = f1();" is sufficient. +if (0) +{ +create temporary table t1 as select 1 as a; +prepare stmt from "select 1 from t1 having count(*) = f1()"; +execute stmt; +call p_verify_reprepare_count(0); +deallocate prepare stmt; +drop temporary table t1; +} + + +--echo # Cleanup +--echo # +--disable_warnings +drop temporary table if exists t1; +drop table if exists t1, t2; +drop procedure if exists p_verify_reprepare_count; +drop procedure if exists p1; +drop function if exists f1; +drop view if exists t1; +drop schema if exists mysqltest; +--enable_warnings diff --git a/mysql-test/t/query_cache_merge.test b/mysql-test/t/query_cache_merge.test index 36b8662f088..5247d29a83c 100644 --- a/mysql-test/t/query_cache_merge.test +++ b/mysql-test/t/query_cache_merge.test @@ -25,6 +25,15 @@ while ($1) } --enable_warnings +# +# In order for the test to pass in --ps-protocol, we must +# set table_definition_cache size to at least 258 elements. +# Otherwise table versions are bound to change between +# prepare and execute, and we will get a constant validation +# error. See WL#4165 for details. +# +set @save_table_definition_cache= @@global.table_definition_cache; +set @@global.table_definition_cache=512; create table t00 (a int) engine=MERGE UNION=(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257) INSERT_METHOD=FIRST; enable_query_log; select count(*) from t00; @@ -36,5 +45,6 @@ show status like "Qcache_queries_in_cache"; drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257,t00; SET @@global.query_cache_size=0; +set @@global.table_definition_cache=@save_table_definition_cache; # End of 4.1 tests diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 921c9579bfb..c57178c1928 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -997,11 +997,10 @@ call p1(); # Altering trigger forcing it use different set of tables drop trigger t1_bi; create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id); -# Until we implement proper mechanism for invalidation of PS/SP when table -# or SP's are changed these two statements will fail with 'Table ... was -# not locked' error (this mechanism should be based on the new TDC). ---error ER_NO_SUCH_TABLE execute stmt1; +# Until we implement proper mechanism for invalidation of SP statements +# invoked whenever a table used in SP changes, this statement will fail with +# 'Table ... does not exist' error. --error ER_NO_SUCH_TABLE call p1(); deallocate prepare stmt1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 51f8d6db1db..221f46605cd 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -778,3 +778,20 @@ set global thread_cache_size =@my_thread_cache_size; --replace_column 2 # show global variables where Variable_name='table_definition_cache' or Variable_name='table_lock_wait_timeout'; + +########################################################################### + +--echo +--echo # -- +--echo # -- Bug#34820: log_output can be set to illegal value. +--echo # -- + +--error ER_WRONG_VALUE_FOR_VAR +SET GLOBAL log_output = ''; + +--error ER_WRONG_VALUE_FOR_VAR +SET GLOBAL log_output = 0; + +--echo +--echo # -- End of Bug#34820. + diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 9203ce9c34e..2607ea57d08 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -202,7 +202,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) { if (mem_root->error_handler) (*mem_root->error_handler)(); - return((void*) 0); /* purecov: inspected */ + DBUG_RETURN((void*) 0); /* purecov: inspected */ } mem_root->block_num++; next->next= *prev; diff --git a/sql/item.cc b/sql/item.cc index 76f3a818826..96408a70bdd 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3161,6 +3161,49 @@ void Item_param::print(String *str, enum_query_type query_type) } +/** + Preserve the original parameter types and values + when re-preparing a prepared statement. + + @details Copy parameter type information and conversion + function pointers from a parameter of the old statement + to the corresponding parameter of the new one. + + Move parameter values from the old parameters to the new + one. We simply "exchange" the values, which allows + to save on allocation and character set conversion in + case a parameter is a string or a blob/clob. + + The old parameter gets the value of this one, which + ensures that all memory of this parameter is freed + correctly. + + @param[in] src parameter item of the original + prepared statement +*/ + +void +Item_param::set_param_type_and_swap_value(Item_param *src) +{ + unsigned_flag= src->unsigned_flag; + param_type= src->param_type; + set_param_func= src->set_param_func; + item_type= src->item_type; + item_result_type= src->item_result_type; + + collation.set(src->collation); + maybe_null= src->maybe_null; + null_value= src->null_value; + max_length= src->max_length; + decimals= src->decimals; + state= src->state; + value= src->value; + + decimal_value.swap(src->decimal_value); + str_value.swap(src->str_value); + str_value_ptr.swap(src->str_value_ptr); +} + /**************************************************************************** Item_copy_string ****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index cd8bb4faccb..465d6f4d54c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1684,6 +1684,7 @@ public: bool eq(const Item *item, bool binary_cmp) const; /** Item is a argument to a limit clause. */ bool limit_clause_param; + void set_param_type_and_swap_value(Item_param *from); }; diff --git a/sql/my_decimal.h b/sql/my_decimal.h index e73e0d4080d..0e79f70ab4e 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -114,6 +114,14 @@ public: bool sign() const { return decimal_t::sign; } void sign(bool s) { decimal_t::sign= s; } uint precision() const { return intg + frac; } + + /** Swap two my_decimal values */ + void swap(my_decimal &rhs) + { + swap_variables(my_decimal, *this, rhs); + /* Swap the buffer pointers back */ + swap_variables(decimal_digit_t *, buf, rhs.buf); + } }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 69f214d95f3..0060e7873e1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -259,6 +259,21 @@ protected: #define USER_VARS_HASH_SIZE 16 #define TABLE_OPEN_CACHE_MIN 64 #define TABLE_OPEN_CACHE_DEFAULT 64 +#define TABLE_DEF_CACHE_DEFAULT 256 +/** + We must have room for at least 256 table definitions in the table + cache, since otherwise there is no chance prepared + statements that use these many tables can work. + Prepared statements use table definition cache ids (table_map_id) + as table version identifiers. If the table definition + cache size is less than the number of tables used in a statement, + the contents of the table definition cache is guaranteed to rotate + between a prepare and execute. This leads to stable validation + errors. In future we shall use more stable version identifiers, + for now the only solution is to ensure that the table definition + cache can contain at least all tables of a given statement. +*/ +#define TABLE_DEF_CACHE_MIN 256 /* Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper @@ -670,6 +685,31 @@ const char *set_thd_proc_info(THD *thd, const char *info, const char *calling_file, const unsigned int calling_line); +/** + Enumerate possible types of a table from re-execution + standpoint. + TABLE_LIST class has a member of this type. + At prepared statement prepare, this member is assigned a value + as of the current state of the database. Before (re-)execution + of a prepared statement, we check that the value recorded at + prepare matches the type of the object we obtained from the + table definition cache. + + @sa check_and_update_table_version() + @sa Execute_observer + @sa Prepared_statement::reprepare() +*/ + +enum enum_table_ref_type +{ + /** Initial value set by the parser */ + TABLE_REF_NULL= 0, + TABLE_REF_VIEW, + TABLE_REF_BASE_TABLE, + TABLE_REF_I_S_TABLE, + TABLE_REF_TMP_TABLE +}; + /* External variables */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0c1ad3ffc69..e34356215e2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1957,9 +1957,11 @@ static BOOL WINAPI console_event_handler( DWORD type ) between main thread doing initialization and CTRL-C thread doing cleanup, which can result into crash. */ +#ifndef EMBEDDED_LIBRARY if(hEventShutdown) kill_mysql(); else +#endif sql_print_warning("CTRL-C ignored during startup"); DBUG_RETURN(TRUE); } @@ -2843,6 +2845,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) by the stored procedures code. */ if (thd->spcont && + ! (MyFlags & ME_NO_SP_HANDLER) && thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) { /* @@ -2852,7 +2855,8 @@ int my_message_sql(uint error, const char *str, myf MyFlags) DBUG_RETURN(0); } - if (!thd->no_warnings_for_error) + if (!thd->no_warnings_for_error && + !(MyFlags & ME_NO_WARNING_FOR_ERROR)) { /* Suppress infinite recursion if there a memory allocation error @@ -3092,6 +3096,7 @@ SHOW_VAR com_status_vars[]= { {"stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS}, {"stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS}, {"stmt_prepare", (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS}, + {"stmt_reprepare", (char*) offsetof(STATUS_VAR, com_stmt_reprepare), SHOW_LONG_STATUS}, {"stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS}, {"stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS}, {"truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS}, @@ -3180,7 +3185,7 @@ static int init_common_variables(const char *conf_file_name, int argc, We have few debug-only commands in com_status_vars, only visible in debug builds. for simplicity we enable the assert only in debug builds - There are 7 Com_ variables which don't have corresponding SQLCOM_ values: + There are 8 Com_ variables which don't have corresponding SQLCOM_ values: (TODO strictly speaking they shouldn't be here, should not have Com_ prefix that is. Perhaps Stmt_ ? Comstmt_ ? Prepstmt_ ?) @@ -3189,6 +3194,7 @@ static int init_common_variables(const char *conf_file_name, int argc, Com_stmt_execute => com_stmt_execute Com_stmt_fetch => com_stmt_fetch Com_stmt_prepare => com_stmt_prepare + Com_stmt_reprepare => com_stmt_reprepare Com_stmt_reset => com_stmt_reset Com_stmt_send_long_data => com_stmt_send_long_data @@ -3197,7 +3203,7 @@ static int init_common_variables(const char *conf_file_name, int argc, of SQLCOM_ constants. */ compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == - SQLCOM_END + 7); + SQLCOM_END + 8); #endif load_defaults(conf_file_name, groups, &argc, &argv); @@ -6766,7 +6772,8 @@ The minimum value for this variable is 4096.", {"table_definition_cache", OPT_TABLE_DEF_CACHE, "The number of cached table definitions.", (uchar**) &table_def_size, (uchar**) &table_def_size, - 0, GET_ULONG, REQUIRED_ARG, 128, 1, 512*1024L, 0, 1, 0}, + 0, GET_ULONG, REQUIRED_ARG, TABLE_DEF_CACHE_DEFAULT, TABLE_DEF_CACHE_MIN, + 512*1024L, 0, 1, 0}, {"table_open_cache", OPT_TABLE_OPEN_CACHE, "The number of cached open tables.", (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e5709f418f7..b428909d9b7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2314,9 +2314,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, table deletes. */ if ((thd->lex->sql_command != SQLCOM_DELETE)) -#ifdef NOT_USED - if ((thd->lex->sql_command != SQLCOM_UPDATE)) -#endif { /* Get best non-covering ROR-intersection plan and prepare data for diff --git a/sql/set_var.cc b/sql/set_var.cc index fd81dc1a867..7d9d88f0281 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1667,6 +1667,14 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) strmov(buff, "NULL"); goto err; } + + if (!m_allow_empty_value && + res->length() == 0) + { + buff[0]= 0; + goto err; + } + var->save_result.ulong_value= ((ulong) find_set(enum_names, res->c_ptr(), res->length(), @@ -1682,10 +1690,19 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) else { ulonglong tmp= var->value->val_int(); - /* - For when the enum is made to contain 64 elements, as 1ULL<<64 is - undefined, we guard with a "count<64" test. - */ + + if (!m_allow_empty_value && + tmp == 0) + { + buff[0]= '0'; + buff[1]= 0; + goto err; + } + + /* + For when the enum is made to contain 64 elements, as 1ULL<<64 is + undefined, we guard with a "count<64" test. + */ if (unlikely((tmp >= ((ULL(1)) << enum_names->count)) && (enum_names->count < 64))) { @@ -2385,32 +2402,51 @@ static int sys_check_log_path(THD *thd, set_var *var) MY_STAT f_stat; String str(buff, sizeof(buff), system_charset_info), *res; const char *log_file_str; - + size_t path_length; + if (!(res= var->value->val_str(&str))) goto err; log_file_str= res->c_ptr(); bzero(&f_stat, sizeof(MY_STAT)); - (void) unpack_filename(path, log_file_str); - if (my_stat(path, &f_stat, MYF(0))) + path_length= unpack_filename(path, log_file_str); + + if (!path_length) { - /* Check if argument is a file and we have 'write' permission */ - if (!MY_S_ISREG(f_stat.st_mode) || - !(f_stat.st_mode & MY_S_IWRITE)) - goto err; + /* File name is empty. */ + + goto err; } - else + + if (my_stat(path, &f_stat, MYF(0))) { - size_t path_length; /* - Check if directory exists and - we have permission to create file & write to file + A file system object exists. Check if argument is a file and we have + 'write' permission. */ - (void) dirname_part(path, log_file_str, &path_length); - if (my_access(path, (F_OK|W_OK))) + + if (!MY_S_ISREG(f_stat.st_mode) || + !(f_stat.st_mode & MY_S_IWRITE)) goto err; + + return 0; } + + /* Get dirname of the file path. */ + (void) dirname_part(path, log_file_str, &path_length); + + /* Dirname is empty if file path is relative. */ + if (!path_length) + return 0; + + /* + Check if directory exists and we have permission to create file and + write to file. + */ + if (my_access(path, (F_OK|W_OK))) + goto err; + return 0; err: diff --git a/sql/set_var.h b/sql/set_var.h index 290d1bf0eb1..603c3114d0e 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -74,7 +74,8 @@ public: sys_var(const char *name_arg, sys_after_update_func func= NULL, Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) :name(name_arg), after_update(func), no_support_one_shot(1), - binlog_status(binlog_status_arg) + binlog_status(binlog_status_arg), + m_allow_empty_value(TRUE) {} virtual ~sys_var() {} void chain_sys_var(sys_var_chain *chain_arg) @@ -109,8 +110,16 @@ public: virtual bool is_readonly() const { return 0; } virtual sys_var_pluginvar *cast_pluginvar() { return 0; } +protected: + void set_allow_empty_value(bool allow_empty_value) + { + m_allow_empty_value= allow_empty_value; + } + private: const Binlog_status_enum binlog_status; + + bool m_allow_empty_value; }; @@ -878,8 +887,11 @@ public: sys_var_log_output(sys_var_chain *chain, const char *name_arg, ulong *value_arg, TYPELIB *typelib, sys_after_update_func func) :sys_var(name_arg,func), value(value_arg), enum_names(typelib) - { chain_sys_var(chain); } - bool check(THD *thd, set_var *var) + { + chain_sys_var(chain); + set_allow_empty_value(FALSE); + } + virtual bool check(THD *thd, set_var *var) { return check_set(thd, var, enum_names); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5b9d0ce8617..3fd35fd0c76 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6121,8 +6121,15 @@ ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." ER_SLAVE_CORRUPT_EVENT eng "Corrupted replication event was detected" + ER_LOAD_DATA_INVALID_COLUMN eng "Invalid column reference (%-.64s) in LOAD DATA" ER_LOG_PURGE_NO_FILE eng "Being purged log %s was not found" + +ER_NEED_REPREPARE + eng "Prepared statement needs to be re-prepared" + +ER_PS_REBIND + eng "Prepared statement result set has changed, a rebind needed" diff --git a/sql/sp.cc b/sql/sp.cc index 8637174efde..a1e5e1291ae 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1076,210 +1076,6 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) } -struct st_used_field -{ - const char *field_name; - uint field_length; - enum enum_field_types field_type; - Field *field; -}; - -static struct st_used_field init_fields[]= -{ - { "Db", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "Name", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "Type", 9, MYSQL_TYPE_STRING, 0}, - { "Definer", USER_HOST_BUFF_SIZE, MYSQL_TYPE_STRING, 0}, - { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Security_type", 1, MYSQL_TYPE_STRING, 0}, - { "Comment", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "character_set_client", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { "collation_connection", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { "Database Collation", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { 0, 0, MYSQL_TYPE_STRING, 0} -}; - - -static int -print_field_values(THD *thd, TABLE *table, - struct st_used_field *used_fields, - int type, const char *wild) -{ - Protocol *protocol= thd->protocol; - - if (table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == type) - { - String db_string; - String name_string; - struct st_used_field *used_field= used_fields; - - if (get_field(thd->mem_root, used_field->field, &db_string)) - db_string.set_ascii("", 0); - used_field+= 1; - get_field(thd->mem_root, used_field->field, &name_string); - - if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0)) - { - protocol->prepare_for_resend(); - protocol->store(&db_string); - protocol->store(&name_string); - for (used_field++; - used_field->field_name; - used_field++) - { - switch (used_field->field_type) { - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME tmp_time; - - bzero((char *)&tmp_time, sizeof(tmp_time)); - ((Field_timestamp *) used_field->field)->get_time(&tmp_time); - protocol->store(&tmp_time); - } - break; - default: - { - String tmp_string; - - get_field(thd->mem_root, used_field->field, &tmp_string); - protocol->store(&tmp_string); - } - break; - } - } - if (protocol->write()) - return SP_INTERNAL_ERROR; - } - } - - return SP_OK; -} - - -/** - Implement SHOW STATUS statement for stored routines. - - @param thd Thread context. - @param type Stored routine type - (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION) - @param name_pattern Stored routine name pattern. - - @return Error code. SP_OK is returned on success. Other SP_ constants are - used to indicate about errors. -*/ - -int -sp_show_status_routine(THD *thd, int type, const char *name_pattern) -{ - TABLE *table; - TABLE_LIST tables; - int res; - DBUG_ENTER("sp_show_status_routine"); - - DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || - type == TYPE_ENUM_FUNCTION); - - memset(&tables, 0, sizeof(tables)); - tables.db= (char*)"mysql"; - tables.table_name= tables.alias= (char*)"proc"; - - if (! (table= open_ltable(thd, &tables, TL_READ, 0))) - { - res= SP_OPEN_TABLE_FAILED; - goto done; - } - else - { - Item *item; - List<Item> field_list; - struct st_used_field *used_field; - TABLE_LIST *leaves= 0; - st_used_field used_fields[array_elements(init_fields)]; - - table->use_all_columns(); - memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields)); - /* Init header */ - for (used_field= &used_fields[0]; - used_field->field_name; - used_field++) - { - switch (used_field->field_type) { - case MYSQL_TYPE_TIMESTAMP: - item= new Item_return_date_time(used_field->field_name, - MYSQL_TYPE_DATETIME); - field_list.push_back(item); - break; - default: - item= new Item_empty_string(used_field->field_name, - used_field->field_length); - field_list.push_back(item); - break; - } - } - /* Print header */ - if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF)) - { - res= SP_INTERNAL_ERROR; - goto err_case; - } - - /* - Init fields - - tables is not VIEW for sure => we can pass 0 as condition - */ - thd->lex->select_lex.context.resolve_in_table_list_only(&tables); - setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - &tables, &leaves, FALSE); - for (used_field= &used_fields[0]; - used_field->field_name; - used_field++) - { - Item_field *field= new Item_field(&thd->lex->select_lex.context, - "mysql", "proc", - used_field->field_name); - if (!field || - !(used_field->field= find_field_in_tables(thd, field, &tables, NULL, - 0, REPORT_ALL_ERRORS, 1, - TRUE))) - { - res= SP_INTERNAL_ERROR; - goto err_case1; - } - } - - table->file->ha_index_init(0, 1); - if ((res= table->file->index_first(table->record[0]))) - { - res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR; - goto err_case1; - } - - do - { - res= print_field_values(thd, table, used_fields, type, name_pattern); - - if (res) - goto err_case1; - } - while (!table->file->index_next(table->record[0])); - - res= SP_OK; - } - -err_case1: - my_eof(thd); -err_case: - table->file->ha_index_end(); - close_thread_tables(thd); -done: - DBUG_RETURN(res); -} - - /** Drop all routines in database 'db' @@ -49,9 +49,6 @@ bool sp_show_create_routine(THD *thd, int type, sp_name *name); int -sp_show_status_routine(THD *thd, int type, const char *wild); - -int sp_create_routine(THD *thd, int type, sp_head *sp); int diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e342a3e9451..c450c9dd25d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1072,6 +1072,7 @@ sp_head::execute(THD *thd) LEX *old_lex; Item_change_list old_change_list; String old_packet; + Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; @@ -1139,6 +1140,25 @@ sp_head::execute(THD *thd) thd->variables.sql_mode= m_sql_mode; save_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= 0; + /** + When inside a substatement (a stored function or trigger + statement), clear the metadata observer in THD, if any. + Remember the value of the observer here, to be able + to restore it when leaving the substatement. + + We reset the observer to suppress errors when a substatement + uses temporary tables. If a temporary table does not exist + at start of the main statement, it's not prelocked + and thus is not validated with other prelocked tables. + + Later on, when the temporary table is opened, metadata + versions mismatch, expectedly. + + The proper solution for the problem is to re-validate tables + of substatements (Bug#12257, Bug#27011, Bug#32868, Bug#33000), + but it's not implemented yet. + */ + thd->m_reprepare_observer= 0; /* It is also more efficient to save/restore current thd->lex once when @@ -1301,6 +1321,7 @@ sp_head::execute(THD *thd) thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; thd->abort_on_warning= save_abort_on_warning; + thd->m_reprepare_observer= save_reprepare_observer; thd->stmt_arena= old_arena; state= EXECUTED; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 92eb68dc2fa..0b33abcfba2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -695,6 +695,8 @@ my_bool acl_reload(THD *thd) tables[0].next_local= tables[0].next_global= tables+1; tables[1].next_local= tables[1].next_global= tables+2; tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; + tables[0].skip_temporary= tables[1].skip_temporary= + tables[2].skip_temporary= TRUE; if (simple_open_n_lock_tables(thd, tables)) { @@ -3537,7 +3539,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table) bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); - DBUG_ENTER("grant_load"); + DBUG_ENTER("grant_load_procs_priv"); (void) hash_init(&proc_priv_hash,system_charset_info, 0,0,0, (hash_get_key) get_grant_table, 0,0); @@ -3721,6 +3723,7 @@ static my_bool grant_reload_procs_priv(THD *thd) table.alias= table.table_name= (char*) "procs_priv"; table.db= (char *) "mysql"; table.lock_type= TL_READ; + table.skip_temporary= 1; if (simple_open_n_lock_tables(thd, &table)) { @@ -3786,7 +3789,7 @@ my_bool grant_reload(THD *thd) tables[0].db= tables[1].db= (char *) "mysql"; tables[0].next_local= tables[0].next_global= tables+1; tables[0].lock_type= tables[1].lock_type= TL_READ; - + tables[0].skip_temporary= tables[1].skip_temporary= TRUE; /* To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b680bbc1308..d25057789ac 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -345,26 +345,9 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, if (!(share= alloc_table_share(table_list, key, key_length))) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif DBUG_RETURN(0); } -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - // We need a write lock to be able to add a new entry - pthread_mutex_unlock(&LOCK_open); - pthread_mutex_lock(&LOCK_open); - /* Check that another thread didn't insert the same table in between */ - if ((old_share= hash_search(&table_def_cache, (uchar*) key, key_length))) - { - (void) pthread_mutex_lock(&share->mutex); - free_table_share(share); - share= old_share; - goto found; - } -#endif - /* Lock mutex to be able to read table definition from file without conflicts @@ -388,29 +371,11 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, if (my_hash_insert(&table_def_cache, (uchar*) share)) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); - (void) pthread_mutex_unlock(&share->mutex); -#endif free_table_share(share); DBUG_RETURN(0); // return error } -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif if (open_table_def(thd, share, db_flags)) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - /* - No such table or wrong table definition file - Lock first the table cache and then the mutex. - This will ensure that no other thread is using the share - structure. - */ - (void) pthread_mutex_unlock(&share->mutex); - (void) pthread_mutex_lock(&LOCK_open); - (void) pthread_mutex_lock(&share->mutex); -#endif *error= share->error; (void) hash_delete(&table_def_cache, (uchar*) share); DBUG_RETURN(0); @@ -429,9 +394,6 @@ found: /* We must do a lock to ensure that the structure is initialized */ (void) pthread_mutex_lock(&share->mutex); -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif if (share->error) { /* Table definition contained an error */ @@ -618,52 +580,6 @@ void release_table_share(TABLE_SHARE *share, enum release_type type) } pthread_mutex_unlock(&share->mutex); DBUG_VOID_RETURN; - - -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - if (to_be_deleted) - { - /* - We must try again with new locks as we must get LOCK_open - before share->mutex - */ - pthread_mutex_unlock(&share->mutex); - pthread_mutex_lock(&LOCK_open); - pthread_mutex_lock(&share->mutex); - if (!share->ref_count) - { // No one is using this now - TABLE_SHARE *name_lock; - if (share->replace_with_name_lock && (name_lock=get_name_lock(share))) - { - /* - This code is execured when someone does FLUSH TABLES while on has - locked tables. - */ - (void) hash_search(&def_cache,(uchar*) key,key_length); - hash_replace(&def_cache, def_cache.current_record,(uchar*) name_lock); - } - else - { - /* Remove table definition */ - hash_delete(&def_cache,(uchar*) share); - } - pthread_mutex_unlock(&LOCK_open); - free_table_share(share); - } - else - { - pthread_mutex_unlock(&LOCK_open); - if (type == RELEASE_WAIT_FOR_DROP) - wait_for_table(share, "Waiting for close"); - else - pthread_mutex_unlock(&share->mutex); - } - } - else if (type == RELEASE_WAIT_FOR_DROP) - wait_for_table(share, "Waiting for close"); - else - pthread_mutex_unlock(&share->mutex); -#endif } @@ -3801,6 +3717,73 @@ void assign_new_table_id(TABLE_SHARE *share) DBUG_VOID_RETURN; } + +/** + Compare metadata versions of an element obtained from the table + definition cache and its corresponding node in the parse tree. + + @details If the new and the old values mismatch, invoke + Metadata_version_observer. + At prepared statement prepare, all TABLE_LIST version values are + NULL and we always have a mismatch. But there is no observer set + in THD, and therefore no error is reported. Instead, we update + the value in the parse tree, effectively recording the original + version. + At prepared statement execute, an observer may be installed. If + there is a version mismatch, we push an error and return TRUE. + + For conventional execution (no prepared statements), the + observer is never installed. + + @sa Execute_observer + @sa check_prepared_statement() to see cases when an observer is installed + @sa TABLE_LIST::is_table_ref_id_equal() + @sa TABLE_SHARE::get_table_ref_id() + + @param[in] thd used to report errors + @param[in,out] tables TABLE_LIST instance created by the parser + Metadata version information in this object + is updated upon success. + @param[in] table_share an element from the table definition cache + + @retval TRUE an error, which has been reported + @retval FALSE success, version in TABLE_LIST has been updated +*/ + +bool +check_and_update_table_version(THD *thd, + TABLE_LIST *tables, TABLE_SHARE *table_share) +{ + if (! tables->is_table_ref_id_equal(table_share)) + { + if (thd->m_reprepare_observer && + thd->m_reprepare_observer->report_error(thd)) + { + /* + Version of the table share is different from the + previous execution of the prepared statement, and it is + unacceptable for this SQLCOM. Error has been reported. + */ + DBUG_ASSERT(thd->is_error()); + return TRUE; + } + /* Always maintain the latest version and type */ + tables->set_table_ref_id(table_share); + } + +#ifndef DBUG_OFF + /* Spuriously reprepare each statement. */ + if (_db_strict_keyword_("reprepare_each_statement") && + thd->m_reprepare_observer && thd->stmt_arena->is_reprepared == FALSE) + { + thd->m_reprepare_observer->report_error(thd); + return TRUE; + } +#endif + + return FALSE; +} + /* Load a table definition from file and open unireg table @@ -3846,6 +3829,12 @@ retry: if (share->is_view) { + /* + This table is a view. Validate its metadata version: in particular, + that it was a view when the statement was prepared. + */ + if (check_and_update_table_version(thd, table_list, share)) + goto err; if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) goto err; @@ -3863,6 +3852,26 @@ retry: release_table_share(share, RELEASE_NORMAL); DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0); } + else if (table_list->view) + { + /* + We're trying to open a table for what was a view. + This can only happen during (re-)execution. + At prepared statement prepare the view has been opened and + merged into the statement parse tree. After that, someone + performed a DDL and replaced the view with a base table. + Don't try to open the table inside a prepared statement, + invalidate it instead. + + Note, the assert below is known to fail inside stored + procedures (Bug#27011). + */ + DBUG_ASSERT(thd->m_reprepare_observer); + check_and_update_table_version(thd, table_list, share); + /* Always an error. */ + DBUG_ASSERT(thd->is_error()); + goto err; + } if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) goto err; @@ -4464,8 +4473,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) */ if (tables->schema_table) { - if (!mysql_schema_table(thd, thd->lex, tables)) + /* + If this information_schema table is merged into a mergeable + view, ignore it for now -- it will be filled when its respective + TABLE_LIST is processed. This code works only during re-execution. + */ + if (tables->view) + goto process_view_routines; + if (!mysql_schema_table(thd, thd->lex, tables) && + !check_and_update_table_version(thd, tables, tables->table->s)) + { continue; + } DBUG_RETURN(-1); } (*counter)++; @@ -4613,6 +4632,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) } tables->table->grant= tables->grant; + /* Check and update metadata version of a base table. */ + if (check_and_update_table_version(thd, tables, tables->table->s)) + { + result= -1; + goto err; + } + /* Attach MERGE children if not locked already. */ DBUG_PRINT("tcache", ("is parent: %d is child: %d", test(tables->table->child_l), @@ -4671,7 +4697,11 @@ process_view_routines: error happens on a MERGE child, clear the parents TABLE reference. */ if (tables->parent_l) + { + if (tables->parent_l->next_global == tables->parent_l->table->child_l) + tables->parent_l->next_global= *tables->parent_l->table->child_last_l; tables->parent_l->table= NULL; + } tables->table= NULL; } DBUG_PRINT("tcache", ("returning: %d", result)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5ee4f3dea02..afa9777e00a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -198,6 +198,19 @@ bool foreign_key_prefix(Key *a, Key *b) ** Thread specific functions ****************************************************************************/ +/** Push an error to the error stack and return TRUE for now. */ + +bool +Reprepare_observer::report_error(THD *thd) +{ + my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER)); + + m_invalidated= TRUE; + + return TRUE; +} + + Open_tables_state::Open_tables_state(ulong version_arg) :version(version_arg), state_flags(0U) { @@ -2770,7 +2783,8 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 && handler_tables == 0 && derived_tables == 0 && lock == 0 && locked_tables == 0 && - prelocked_mode == NON_PRELOCKED); + prelocked_mode == NON_PRELOCKED && + m_reprepare_observer == NULL); set_open_tables_state(backup); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 446b7f163d9..a86b4d36d00 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -23,6 +23,51 @@ #include "log.h" #include "rpl_tblmap.h" +/** + An interface that is used to take an action when + the locking module notices that a table version has changed + since the last execution. "Table" here may refer to any kind of + table -- a base table, a temporary table, a view or an + information schema table. + + When we open and lock tables for execution of a prepared + statement, we must verify that they did not change + since statement prepare. If some table did change, the statement + parse tree *may* be no longer valid, e.g. in case it contains + optimizations that depend on table metadata. + + This class provides an interface (a method) that is + invoked when such a situation takes place. + The implementation of the method simply reports an error, but + the exact details depend on the nature of the SQL statement. + + At most 1 instance of this class is active at a time, in which + case THD::m_reprepare_observer is not NULL. + + @sa check_and_update_table_version() for details of the + version tracking algorithm + + @sa Open_tables_state::m_reprepare_observer for the life cycle + of metadata observers. +*/ + +class Reprepare_observer +{ +public: + /** + Check if a change of metadata is OK. In future + the signature of this method may be extended to accept the old + and the new versions, but since currently the check is very + simple, we only need the THD to report an error. + */ + bool report_error(THD *thd); + bool is_invalidated() const { return m_invalidated; } + void reset_reprepare_observer() { m_invalidated= FALSE; } +private: + bool m_invalidated; +}; + + class Relay_log_info; class Query_log_event; @@ -406,6 +451,7 @@ typedef struct system_status_var ulong filesort_scan_count; /* Prepared statements and binary protocol */ ulong com_stmt_prepare; + ulong com_stmt_reprepare; ulong com_stmt_execute; ulong com_stmt_send_long_data; ulong com_stmt_fetch; @@ -436,7 +482,7 @@ void free_tmp_table(THD *thd, TABLE *entry); /* The following macro is to make init of Query_arena simpler */ #ifndef DBUG_OFF -#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 +#define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE; #else #define INIT_ARENA_DBUG_INFO #endif @@ -452,6 +498,7 @@ public: MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF bool is_backup_arena; /* True if this arena is used for backup. */ + bool is_reprepared; #endif /* The states relfects three diffrent life cycles for three @@ -789,6 +836,20 @@ class Open_tables_state { public: /** + As part of class THD, this member is set during execution + of a prepared statement. When it is set, it is used + by the locking subsystem to report a change in table metadata. + + When Open_tables_state part of THD is reset to open + a system or INFORMATION_SCHEMA table, the member is cleared + to avoid spurious ER_NEED_REPREPARE errors -- system and + INFORMATION_SCHEMA tables are not subject to metadata version + tracking. + @sa check_and_update_table_version() + */ + Reprepare_observer *m_reprepare_observer; + + /** List of regular tables in use by this thread. Contains temporary and base tables that were opened with @see open_tables(). */ @@ -891,6 +952,7 @@ public: extra_lock= lock= locked_tables= 0; prelocked_mode= NON_PRELOCKED; state_flags= 0U; + m_reprepare_observer= NULL; } }; @@ -2812,6 +2874,20 @@ public: #define CF_STATUS_COMMAND 4 #define CF_SHOW_TABLE_COMMAND 8 #define CF_WRITE_LOGS_COMMAND 16 +/** + Must be set for SQL statements that may contain + Item expressions and/or use joins and tables. + Indicates that the parse tree of such statement may + contain rule-based optimizations that depend on metadata + (i.e. number of columns in a table), and consequently + that the statement must be re-prepared whenever + referenced metadata changes. Must not be set for + statements that themselves change metadata, e.g. RENAME, + ALTER and other DDL, since otherwise will trigger constant + reprepare. Consequently, complex item expressions and + joins are currently prohibited in these statements. +*/ +#define CF_REEXECUTION_FRAGILE 32 /* Functions in sql_class.cc */ diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 5c4e93d4c74..d33680e1e0b 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -111,7 +111,8 @@ class Select_materialize: public select_union select_result *result; /**< the result object of the caller (PS or SP) */ public: Materialized_cursor *materialized_cursor; - Select_materialize(select_result *result_arg) :result(result_arg) {} + Select_materialize(select_result *result_arg) + :result(result_arg), materialized_cursor(0) {} virtual bool send_fields(List<Item> &list, uint flags); }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ddcec92a0d3..ee251e6511b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -200,45 +200,56 @@ void init_update_queries(void) { bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags)); - sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - - sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE; + + sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND; @@ -262,7 +273,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND; @@ -270,9 +281,11 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND | - CF_SHOW_TABLE_COMMAND); + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | - CF_SHOW_TABLE_COMMAND); + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); /* The following is used to preserver CF_ROW_COUNT during the @@ -280,7 +293,7 @@ void init_update_queries(void) last called (or executed) statement is preserved. See mysql_execute_command() for how CF_ROW_COUNT is used. */ - sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT; + sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT; /* @@ -4315,20 +4328,6 @@ create_sp_error: } break; } -#ifdef NOT_USED - case SQLCOM_SHOW_STATUS_PROC: - { - res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE, - (lex->wild ? lex->wild->ptr() : NullS)); - break; - } - case SQLCOM_SHOW_STATUS_FUNC: - { - res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION, - (lex->wild ? lex->wild->ptr() : NullS)); - break; - } -#endif #ifndef DBUG_OFF case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_FUNC_CODE: diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 091cc18114b..3036b36f8fa 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -155,21 +155,28 @@ public: virtual void cleanup_stmt(); bool set_name(LEX_STRING *name); inline void close_cursor() { delete cursor; cursor= 0; } - + inline bool is_in_use() { return flags & (uint) IS_IN_USE; } + inline bool is_protocol_text() const { return protocol == &thd->protocol_text; } bool prepare(const char *packet, uint packet_length); - bool execute(String *expanded_query, bool open_cursor); + bool execute_loop(String *expanded_query, + bool open_cursor, + uchar *packet_arg, uchar *packet_end_arg); /* Destroy this statement */ - bool deallocate(); + void deallocate(); private: /** - Store the parsed tree of a prepared statement here. - */ - LEX main_lex; - /** The memory root to allocate parsed tree elements (instances of Item, SELECT_LEX and other classes). */ MEM_ROOT main_mem_root; +private: + bool set_db(const char *db, uint db_length); + bool set_parameters(String *expanded_query, + uchar *packet, uchar *packet_end); + bool execute(String *expanded_query, bool open_cursor); + bool reprepare(); + bool validate_metadata(Prepared_statement *copy); + void swap_prepared_statement(Prepared_statement *copy); }; @@ -198,7 +205,7 @@ inline bool is_param_null(const uchar *pos, ulong param_no) */ static Prepared_statement * -find_prepared_statement(THD *thd, ulong id, const char *where) +find_prepared_statement(THD *thd, ulong id) { /* To strictly separate namespaces of SQL prepared statements and C API @@ -208,12 +215,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where) Statement *stmt= thd->stmt_map.find(id); if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT) - { - char llbuf[22]; - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf), - where); - return 0; - } + return NULL; + return (Prepared_statement *) stmt; } @@ -945,6 +948,55 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, #endif /*!EMBEDDED_LIBRARY*/ +/** + Setup data conversion routines using an array of parameter + markers from the original prepared statement. + Swap the parameter data of the original prepared + statement to the new one. + + Used only when we re-prepare a prepared statement. + There are two reasons for this function to exist: + + 1) In the binary client/server protocol, parameter metadata + is sent only at first execute. Consequently, if we need to + reprepare a prepared statement at a subsequent execution, + we may not have metadata information in the packet. + In that case we use the parameter array of the original + prepared statement to setup parameter types of the new + prepared statement. + + 2) In the binary client/server protocol, we may supply + long data in pieces. When the last piece is supplied, + we assemble the pieces and convert them from client + character set to the connection character set. After + that the parameter value is only available inside + the parameter, the original pieces are lost, and thus + we can only assign the corresponding parameter of the + reprepared statement from the original value. + + @param[out] param_array_dst parameter markers of the new statement + @param[in] param_array_src parameter markers of the original + statement + @param[in] param_count total number of parameters. Is the + same in src and dst arrays, since + the statement query is the same + + @return this function never fails +*/ + +static void +swap_parameter_array(Item_param **param_array_dst, + Item_param **param_array_src, + uint param_count) +{ + Item_param **dst= param_array_dst; + Item_param **src= param_array_src; + Item_param **end= param_array_dst + param_count; + + for (; dst < end; ++src, ++dst) + (*dst)->set_param_type_and_swap_value(*src); +} + /** Assign prepared statement parameters from user variables. @@ -1268,7 +1320,7 @@ error: */ static int mysql_test_select(Prepared_statement *stmt, - TABLE_LIST *tables, bool text_protocol) + TABLE_LIST *tables) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1304,7 +1356,7 @@ static int mysql_test_select(Prepared_statement *stmt, */ if (unit->prepare(thd, 0, 0)) goto error; - if (!lex->describe && !text_protocol) + if (!lex->describe && !stmt->is_protocol_text()) { /* Make copy of item list, as change_columns may change it */ List<Item> fields(lex->select_lex.item_list); @@ -1396,6 +1448,43 @@ error: /** + Validate and prepare for execution CALL statement expressions. + + @param stmt prepared statement + @param tables list of tables used in this query + @param value_list list of expressions + + @retval FALSE success + @retval TRUE error, error message is set in THD +*/ + +static bool mysql_test_call_fields(Prepared_statement *stmt, + TABLE_LIST *tables, + List<Item> *value_list) +{ + DBUG_ENTER("mysql_test_call_fields"); + + List_iterator<Item> it(*value_list); + THD *thd= stmt->thd; + Item *item; + + if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) || + open_normal_and_derived_tables(thd, tables, 0)) + goto err; + + while ((item= it++)) + { + if (!item->fixed && item->fix_fields(thd, it.ref()) || + item->check_cols(1)) + goto err; + } + DBUG_RETURN(FALSE); +err: + DBUG_RETURN(TRUE); +} + + +/** Check internal SELECT of the prepared command. @param stmt prepared statement @@ -1516,6 +1605,17 @@ static bool mysql_test_create_table(Prepared_statement *stmt) res= select_like_stmt_test(stmt, 0, 0); } + else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE) + { + /* + Check that the source table exist, and also record + its metadata version. Even though not strictly necessary, + we validate metadata of all CREATE TABLE statements, + which keeps metadata validation code simple. + */ + if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0)) + DBUG_RETURN(TRUE); + } /* put tables back for PS rexecuting */ lex->link_first_table_back(create_table, link_to_local); @@ -1712,8 +1812,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, TRUE error, error message is set in THD (but not sent) */ -static bool check_prepared_statement(Prepared_statement *stmt, - bool text_protocol) +static bool check_prepared_statement(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1754,9 +1853,23 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_DELETE: res= mysql_test_delete(stmt, tables); break; - + /* The following allow WHERE clause, so they must be tested like SELECT */ + case SQLCOM_SHOW_DATABASES: + case SQLCOM_SHOW_TABLES: + case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_EVENTS: + case SQLCOM_SHOW_OPEN_TABLES: + case SQLCOM_SHOW_FIELDS: + case SQLCOM_SHOW_KEYS: + case SQLCOM_SHOW_COLLATIONS: + case SQLCOM_SHOW_CHARSETS: + case SQLCOM_SHOW_VARIABLES: + case SQLCOM_SHOW_STATUS: + case SQLCOM_SHOW_TABLE_STATUS: + case SQLCOM_SHOW_STATUS_PROC: + case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SELECT: - res= mysql_test_select(stmt, tables, text_protocol); + res= mysql_test_select(stmt, tables); if (res == 2) { /* Statement and field info has already been sent */ @@ -1779,6 +1892,9 @@ static bool check_prepared_statement(Prepared_statement *stmt, res= mysql_test_do_fields(stmt, tables, lex->insert_list); break; + case SQLCOM_CALL: + res= mysql_test_call_fields(stmt, tables, &lex->value_list); + break; case SQLCOM_SET_OPTION: res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; @@ -1828,7 +1944,6 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_DROP_INDEX: case SQLCOM_ROLLBACK: case SQLCOM_TRUNCATE: - case SQLCOM_CALL: case SQLCOM_DROP_VIEW: case SQLCOM_REPAIR: case SQLCOM_ANALYZE: @@ -1871,8 +1986,8 @@ static bool check_prepared_statement(Prepared_statement *stmt, break; } if (res == 0) - DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) || - thd->protocol->flush())); + DBUG_RETURN(stmt->is_protocol_text() ? + FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush())); error: DBUG_RETURN(TRUE); } @@ -2121,8 +2236,13 @@ void mysql_sql_stmt_prepare(THD *thd) If there is a statement with the same name, remove it. It is ok to remove old and fail to insert a new one at the same time. */ - if (stmt->deallocate()) + if (stmt->is_in_use()) + { + my_error(ER_PS_NO_RECURSION, MYF(0)); DBUG_VOID_RETURN; + } + + stmt->deallocate(); } if (! (query= get_dynamic_sql_string(lex, &query_len)) || @@ -2308,11 +2428,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) ulong flags= (ulong) packet[4]; /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; -#ifndef EMBEDDED_LIBRARY uchar *packet_end= packet + packet_length; -#endif Prepared_statement *stmt; - bool error; + bool open_cursor; DBUG_ENTER("mysql_stmt_execute"); packet+= 9; /* stmt_id + 5 bytes of flags */ @@ -2320,8 +2438,13 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_execute"); DBUG_VOID_RETURN; + } #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(stmt->query, stmt->query_length); @@ -2332,44 +2455,12 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); -#ifndef EMBEDDED_LIBRARY - if (stmt->param_count) - { - uchar *null_array= packet; - if (setup_conversion_functions(stmt, &packet, packet_end) || - stmt->set_params(stmt, null_array, packet, packet_end, - &expanded_query)) - goto set_params_data_err; - } -#else - /* - In embedded library we re-install conversion routines each time - we set params, and also we don't need to parse packet. - So we do it in one function. - */ - if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query)) - goto set_params_data_err; -#endif - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); + open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY); - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. - */ - DBUG_ASSERT(thd->free_list == NULL); + stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); - error= stmt->execute(&expanded_query, - test(flags & (ulong) CURSOR_TYPE_READ_ONLY)); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(), WAIT_PRIOR); DBUG_VOID_RETURN; -set_params_data_err: - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute"); - reset_stmt_params(stmt); - DBUG_VOID_RETURN; } @@ -2415,24 +2506,8 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. - */ - DBUG_ASSERT(thd->free_list == NULL); - - if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params, - &expanded_query)) - goto set_params_data_err; - - (void) stmt->execute(&expanded_query, FALSE); - - DBUG_VOID_RETURN; + (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL); -set_params_data_err: - my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); - reset_stmt_params(stmt); DBUG_VOID_RETURN; } @@ -2458,8 +2533,13 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); status_var_increment(thd->status_var.com_stmt_fetch); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_fetch"); DBUG_VOID_RETURN; + } cursor= stmt->cursor; if (!cursor) @@ -2520,8 +2600,13 @@ void mysql_stmt_reset(THD *thd, char *packet) mysql_reset_thd_for_next_command(thd); status_var_increment(thd->status_var.com_stmt_reset); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_reset"); DBUG_VOID_RETURN; + } stmt->close_cursor(); @@ -2557,15 +2642,15 @@ void mysql_stmt_close(THD *thd, char *packet) thd->main_da.disable_status(); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) DBUG_VOID_RETURN; /* The only way currently a statement can be deallocated when it's in use is from within Dynamic SQL. */ - DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); - (void) stmt->deallocate(); + DBUG_ASSERT(! stmt->is_in_use()); + stmt->deallocate(); general_log_print(thd, thd->command, NullS); DBUG_VOID_RETURN; @@ -2592,14 +2677,15 @@ void mysql_sql_stmt_close(THD *thd) name->str)); if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) - { my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), name->length, name->str, "DEALLOCATE PREPARE"); - return; - } - - if (stmt->deallocate() == 0) + else if (stmt->is_in_use()) + my_error(ER_PS_NO_RECURSION, MYF(0)); + else + { + stmt->deallocate(); my_ok(thd); + } } /** @@ -2633,17 +2719,13 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length < MYSQL_LONG_DATA_HEADER) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data"); DBUG_VOID_RETURN; - } #endif stmt_id= uint4korr(packet); packet+= 4; - if (!(stmt=find_prepared_statement(thd, stmt_id, - "mysql_stmt_send_long_data"))) + if (!(stmt=find_prepared_statement(thd, stmt_id))) DBUG_VOID_RETURN; param_number= uint2korr(packet); @@ -2729,7 +2811,7 @@ Select_fetch_protocol_binary::send_data(List<Item> &fields) ****************************************************************************/ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) - :Statement(&main_lex, &main_mem_root, + :Statement(NULL, &main_mem_root, INITIALIZED, ++thd_arg->statement_id_counter), thd(thd_arg), result(thd_arg), @@ -2800,7 +2882,11 @@ Prepared_statement::~Prepared_statement() like Item_param, don't free everything until free_items() */ free_items(); - delete lex->result; + if (lex) + { + delete lex->result; + delete (st_lex_local *) lex; + } free_root(&main_mem_root, MYF(0)); DBUG_VOID_RETURN; } @@ -2836,6 +2922,34 @@ bool Prepared_statement::set_name(LEX_STRING *name_arg) return name.str == 0; } + +/** + Remember the current database. + + We must reset/restore the current database during execution of + a prepared statement since it affects execution environment: + privileges, @@character_set_database, and other. + + @return Returns an error if out of memory. +*/ + +bool +Prepared_statement::set_db(const char *db_arg, uint db_length_arg) +{ + /* Remember the current database. */ + if (db_arg && db_length_arg) + { + db= this->strmake(db_arg, db_length_arg); + db_length= db_length_arg; + } + else + { + db= NULL; + db_length= 0; + } + return db_arg != NULL && db == NULL; +} + /************************************************************************** Common parts of mysql_[sql]_stmt_prepare, mysql_[sql]_stmt_execute. Essentially, these functions do all the magic of preparing/executing @@ -2877,6 +2991,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ status_var_increment(thd->status_var.com_stmt_prepare); + if (! (lex= new (mem_root) st_lex_local)) + DBUG_RETURN(TRUE); + + if (set_db(thd->db, thd->db_length)) + DBUG_RETURN(TRUE); + /* alloc_query() uses thd->memroot && thd->query, so we should call both of backup_statement() and backup_query_arena() here. @@ -2904,19 +3024,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex->set_trg_event_type_for_tables(); - /* Remember the current database. */ - - if (thd->db && thd->db_length) - { - db= this->strmake(thd->db, thd->db_length); - db_length= thd->db_length; - } - else - { - db= NULL; - db_length= 0; - } - /* While doing context analysis of the query (in check_prepared_statement) we allocate a lot of additional memory: for open tables, JOINs, derived @@ -2940,7 +3047,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ if (error == 0) - error= check_prepared_statement(this, name.str != 0); + error= check_prepared_statement(this); /* Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared @@ -2987,6 +3094,306 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) DBUG_RETURN(error); } + +/** + Assign parameter values either from variables, in case of SQL PS + or from the execute packet. + + @param expanded_query a container with the original SQL statement. + '?' placeholders will be replaced with + their values in case of success. + The result is used for logging and replication + @param packet pointer to execute packet. + NULL in case of SQL PS + @param packet_end end of the packet. NULL in case of SQL PS + + @todo Use a paremeter source class family instead of 'if's, and + support stored procedure variables. + + @retval TRUE an error occurred when assigning a parameter (likely + a conversion error or out of memory, or malformed packet) + @retval FALSE success +*/ + +bool +Prepared_statement::set_parameters(String *expanded_query, + uchar *packet, uchar *packet_end) +{ + bool is_sql_ps= packet == NULL; + bool res= FALSE; + + if (is_sql_ps) + { + /* SQL prepared statement */ + res= set_params_from_vars(this, thd->lex->prepared_stmt_params, + expanded_query); + } + else if (param_count) + { +#ifndef EMBEDDED_LIBRARY + uchar *null_array= packet; + res= (setup_conversion_functions(this, &packet, packet_end) || + set_params(this, null_array, packet, packet_end, expanded_query)); +#else + /* + In embedded library we re-install conversion routines each time + we set parameters, and also we don't need to parse packet. + So we do it in one function. + */ + res= set_params_data(this, expanded_query); +#endif + } + if (res) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), + is_sql_ps ? "EXECUTE" : "mysql_stmt_execute"); + reset_stmt_params(this); + } + return res; +} + + +/** + Execute a prepared statement. Re-prepare it a limited number + of times if necessary. + + Try to execute a prepared statement. If there is a metadata + validation error, prepare a new copy of the prepared statement, + swap the old and the new statements, and try again. + If there is a validation error again, repeat the above, but + perform no more than MAX_REPREPARE_ATTEMPTS. + + @note We have to try several times in a loop since we + release metadata locks on tables after prepared statement + prepare. Therefore, a DDL statement may sneak in between prepare + and execute of a new statement. If this happens repeatedly + more than MAX_REPREPARE_ATTEMPTS times, we give up. + + In future we need to be able to keep the metadata locks between + prepare and execute, but right now open_and_lock_tables(), as + well as close_thread_tables() are buried deep inside + execution code (mysql_execute_command()). + + @return TRUE if an error, FALSE if success + @retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached, + or some general error + @retval FALSE successfully executed the statement, perhaps + after having reprepared it a few times. +*/ + +bool +Prepared_statement::execute_loop(String *expanded_query, + bool open_cursor, + uchar *packet, + uchar *packet_end) +{ + const int MAX_REPREPARE_ATTEMPTS= 3; + Reprepare_observer reprepare_observer; + bool error; + int reprepare_attempt= 0; + + if (set_parameters(expanded_query, packet, packet_end)) + return TRUE; + +reexecute: + reprepare_observer.reset_reprepare_observer(); + + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after validation of the prepared + statement. + */ + DBUG_ASSERT(thd->free_list == NULL); + + /* + Install the metadata observer. If some metadata version is + different from prepare time and an observer is installed, + the observer method will be invoked to push an error into + the error stack. + */ + if (sql_command_flags[lex->sql_command] & + CF_REEXECUTION_FRAGILE) + { + DBUG_ASSERT(thd->m_reprepare_observer == NULL); + thd->m_reprepare_observer = &reprepare_observer; + } + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + + error= execute(expanded_query, open_cursor) || thd->is_error(); + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(), WAIT_PRIOR); + + thd->m_reprepare_observer= NULL; + + if (error && !thd->is_fatal_error && !thd->killed && + reprepare_observer.is_invalidated() && + reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS) + { + DBUG_ASSERT(thd->main_da.sql_errno() == ER_NEED_REPREPARE); + thd->clear_error(); + + error= reprepare(); + + if (! error) /* Success */ + goto reexecute; + } + reset_stmt_params(this); + + return error; +} + + +/** + Reprepare this prepared statement. + + Currently this is implemented by creating a new prepared + statement, preparing it with the original query and then + swapping the new statement and the original one. + + @retval TRUE an error occurred. Possible errors include + incompatibility of new and old result set + metadata + @retval FALSE success, the statement has been reprepared +*/ + +bool +Prepared_statement::reprepare() +{ + char saved_cur_db_name_buf[NAME_LEN+1]; + LEX_STRING saved_cur_db_name= + { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; + LEX_STRING stmt_db_name= { db, db_length }; + bool cur_db_changed; + bool error; + + Prepared_statement copy(thd, &thd->protocol_text); + + status_var_increment(thd->status_var.com_stmt_reprepare); + + if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE, + &cur_db_changed)) + return TRUE; + + error= (name.str && copy.set_name(&name) || + copy.prepare(query, query_length) || + validate_metadata(©)); + + if (cur_db_changed) + mysql_change_db(thd, &saved_cur_db_name, TRUE); + + if (! error) + { + swap_prepared_statement(©); + swap_parameter_array(param_array, copy.param_array, param_count); +#ifndef DBUG_OFF + is_reprepared= TRUE; +#endif + /* + Clear possible warnings during reprepare, it has to be completely + transparent to the user. We use mysql_reset_errors() since + there were no separate query id issued for re-prepare. + Sic: we can't simply silence warnings during reprepare, because if + it's failed, we need to return all the warnings to the user. + */ + mysql_reset_errors(thd, TRUE); + } + return error; +} + + +/** + Validate statement result set metadata (if the statement returns + a result set). + + Currently we only check that the number of columns of the result + set did not change. + This is a helper method used during re-prepare. + + @param[in] copy the re-prepared prepared statement to verify + the metadata of + + @retval TRUE error, ER_PS_NEED_REBIND is reported + @retval FALSE statement return no or compatible metadata +*/ + + +bool Prepared_statement::validate_metadata(Prepared_statement *copy) +{ + /** + If this is an SQL prepared statement or EXPLAIN, + return FALSE -- the metadata of the original SELECT, + if any, has not been sent to the client. + */ + if (is_protocol_text() || lex->describe) + return FALSE; + + if (lex->select_lex.item_list.elements != + copy->lex->select_lex.item_list.elements) + { + /** Column counts mismatch. */ + my_error(ER_PS_REBIND, MYF(0)); + return TRUE; + } + + return FALSE; +} + + +/** + Replace the original prepared statement with a prepared copy. + + This is a private helper that is used as part of statement + reprepare + + @return This function does not return any errors. +*/ + +void +Prepared_statement::swap_prepared_statement(Prepared_statement *copy) +{ + Statement tmp_stmt; + + /* Swap memory roots. */ + swap_variables(MEM_ROOT, main_mem_root, copy->main_mem_root); + + /* Swap the arenas */ + tmp_stmt.set_query_arena(this); + set_query_arena(copy); + copy->set_query_arena(&tmp_stmt); + + /* Swap the statement parent classes */ + tmp_stmt.set_statement(this); + set_statement(copy); + copy->set_statement(&tmp_stmt); + + /* Swap ids back, we need the original id */ + swap_variables(ulong, id, copy->id); + /* Swap mem_roots back, they must continue pointing at the main_mem_roots */ + swap_variables(MEM_ROOT *, mem_root, copy->mem_root); + /* + Swap the old and the new parameters array. The old array + is allocated in the old arena. + */ + swap_variables(Item_param **, param_array, copy->param_array); + /* Swap flags: this is perhaps unnecessary */ + swap_variables(uint, flags, copy->flags); + /* Swap names, the old name is allocated in the wrong memory root */ + swap_variables(LEX_STRING, name, copy->name); + /* Ditto */ + swap_variables(char *, db, copy->db); + + DBUG_ASSERT(db_length == copy->db_length); + DBUG_ASSERT(param_count == copy->param_count); + DBUG_ASSERT(thd == copy->thd); + last_error[0]= '\0'; + last_errno= 0; + /* Do not swap protocols, the copy always has protocol_text */ +} + + /** Execute a prepared statement. @@ -3149,10 +3556,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) DBUG_ASSERT(! (error && cursor)); if (! cursor) - { cleanup_stmt(); - reset_stmt_params(this); - } thd->set_statement(&stmt_backup); thd->stmt_arena= old_stmt_arena; @@ -3186,16 +3590,10 @@ error: /** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */ -bool Prepared_statement::deallocate() +void Prepared_statement::deallocate() { /* We account deallocate in the same manner as mysql_stmt_close */ status_var_increment(thd->status_var.com_stmt_close); - if (flags & (uint) IS_IN_USE) - { - my_error(ER_PS_NO_RECURSION, MYF(0)); - return TRUE; - } /* Statement map calls delete stmt on erase */ thd->stmt_map.erase(this); - return FALSE; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3ef510b8d89..7c847e0817c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4783,9 +4783,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, DBUG_ENTER("mysql_create_like_table"); - /* CREATE TABLE ... LIKE is not allowed for views. */ - src_table->required_type= FRMTYPE_TABLE; - /* By opening source table we guarantee that it exists and no concurrent DDL operation will mess with it. Later we also take an exclusive diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 9d6a2b1b8c8..bfb71db22da 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -853,8 +853,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, Item **conds, uint order_num, ORDER *order) { Item *fake_conds= 0; +#ifndef NO_EMBEDDED_ACCESS_CHECKS TABLE *table= table_list->table; - TABLE_LIST tables; +#endif List<Item> all_fields; SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_update"); @@ -878,9 +879,6 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, table_list->register_want_access(SELECT_ACL); #endif - bzero((char*) &tables,sizeof(tables)); // For ORDER BY - tables.table= table; - tables.alias= table_list->alias; thd->lex->allow_sum_func= 0; if (setup_tables_and_check_access(thd, &select_lex->context, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 25549936f5a..54399c3791c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3582,20 +3582,30 @@ create2: | LIKE table_ident { THD *thd= YYTHD; + TABLE_LIST *src_table; LEX *lex= thd->lex; lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - if (!lex->select_lex.add_table_to_list(thd, $2, NULL, 0, TL_READ)) + src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0, + TL_READ); + if (! src_table) MYSQL_YYABORT; + /* CREATE TABLE ... LIKE is not allowed for views. */ + src_table->required_type= FRMTYPE_TABLE; } | '(' LIKE table_ident ')' { THD *thd= YYTHD; + TABLE_LIST *src_table; LEX *lex= thd->lex; lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0, TL_READ)) + src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0, + TL_READ); + if (! src_table) MYSQL_YYABORT; + /* CREATE TABLE ... LIKE is not allowed for views. */ + src_table->required_type= FRMTYPE_TABLE; } ; diff --git a/sql/table.h b/sql/table.h index 0e0a35b022d..75ddaf69c10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -438,6 +438,105 @@ typedef struct st_table_share return table_map_id; } + /** + Convert unrelated members of TABLE_SHARE to one enum + representing its type. + + @todo perhaps we need to have a member instead of a function. + */ + enum enum_table_ref_type get_table_ref_type() const + { + if (is_view) + return TABLE_REF_VIEW; + switch (tmp_table) { + case NO_TMP_TABLE: + return TABLE_REF_BASE_TABLE; + case SYSTEM_TMP_TABLE: + return TABLE_REF_I_S_TABLE; + default: + return TABLE_REF_TMP_TABLE; + } + } + /** + Return a table metadata version. + * for base tables, we return table_map_id. + It is assigned from a global counter incremented for each + new table loaded into the table definition cache (TDC). + * for temporary tables it's table_map_id again. But for + temporary tables table_map_id is assigned from + thd->query_id. The latter is assigned from a thread local + counter incremented for every new SQL statement. Since + temporary tables are thread-local, each temporary table + gets a unique id. + * for everything else (views, information schema tables), + the version id is zero. + + This choice of version id is a large compromise + to have a working prepared statement validation in 5.1. In + future version ids will be persistent, as described in WL#4180. + + Let's try to explain why and how this limited solution allows + to validate prepared statements. + + Firstly, sets (in mathematical sense) of version numbers + never intersect for different table types. Therefore, + version id of a temporary table is never compared with + a version id of a view, and vice versa. + + Secondly, for base tables, we know that each DDL flushes the + respective share from the TDC. This ensures that whenever + a table is altered or dropped and recreated, it gets a new + version id. + Unfortunately, since elements of the TDC are also flushed on + LRU basis, this choice of version ids leads to false positives. + E.g. when the TDC size is too small, we may have a SELECT + * FROM INFORMATION_SCHEMA.TABLES flush all its elements, which + in turn will lead to a validation error and a subsequent + reprepare of all prepared statements. This is + considered acceptable, since as long as prepared statements are + automatically reprepared, spurious invalidation is only + a performance hit. Besides, no better simple solution exists. + + For temporary tables, using thd->query_id ensures that if + a temporary table was altered or recreated, a new version id is + assigned. This suits validation needs very well and will perhaps + never change. + + Metadata of information schema tables never changes. + Thus we can safely assume 0 for a good enough version id. + + Views are a special and tricky case. A view is always inlined + into the parse tree of a prepared statement at prepare. + Thus, when we execute a prepared statement, the parse tree + will not get modified even if the view is replaced with another + view. Therefore, we can safely choose 0 for version id of + views and effectively never invalidate a prepared statement + when a view definition is altered. Note, that this leads to + wrong binary log in statement-based replication, since we log + prepared statement execution in form Query_log_events + containing conventional statements. But since there is no + metadata locking for views, the very same problem exists for + conventional statements alone, as reported in Bug#25144. The only + difference between prepared and conventional execution is, + effectively, that for prepared statements the race condition + window is much wider. + In 6.0 we plan to support view metadata locking (WL#3726) and + extend table definition cache to cache views (WL#4298). + When this is done, views will be handled in the same fashion + as the base tables. + + Finally, by taking into account table type, we always + track that a change has taken place when a view is replaced + with a base table, a base table is replaced with a temporary + table and so on. + + @sa TABLE_LIST::is_table_ref_id_equal() + */ + ulong get_table_ref_version() const + { + return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id; + } + } TABLE_SHARE; @@ -1233,6 +1332,33 @@ struct TABLE_LIST child_def_version= ~0UL; } + /** + Compare the version of metadata from the previous execution + (if any) with values obtained from the current table + definition cache element. + + @sa check_and_update_table_version() + */ + inline + bool is_table_ref_id_equal(TABLE_SHARE *s) const + { + return (m_table_ref_type == s->get_table_ref_type() && + m_table_ref_version == s->get_table_ref_version()); + } + + /** + Record the value of metadata version of the corresponding + table definition cache element in this parse tree node. + + @sa check_and_update_table_version() + */ + inline + void set_table_ref_id(TABLE_SHARE *s) + { + m_table_ref_type= s->get_table_ref_type(); + m_table_ref_version= s->get_table_ref_version(); + } + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); @@ -1243,6 +1369,10 @@ private: /* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */ ulong child_def_version; + /** See comments for set_metadata_id() */ + enum enum_table_ref_type m_table_ref_type; + /** See comments for set_metadata_id() */ + ulong m_table_ref_version; }; class Item; diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index bc4dcf0bdbb..2784861f48a 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -634,6 +634,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, my_printf_error(0, "MyISAM table '%s' is in use " "(most likely by a MERGE table). Try FLUSH TABLES.", MYF(0), name + dirname_length(name)); + my_errno= HA_ERR_TABLE_EXIST; goto err; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 0df2d4ed4a5..350c14926cd 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11132,7 +11132,7 @@ static void test_bug4236() int rc; MYSQL_STMT backup; - myheader("test_bug4296"); + myheader("test_bug4236"); stmt= mysql_stmt_init(mysql); @@ -17383,6 +17383,124 @@ static void test_bug28386() DBUG_VOID_RETURN; } +static void test_wl4166() +{ + MYSQL_STMT *stmt; + int int_data; + char str_data[50]; + char tiny_data; + short small_data; + longlong big_data; + float real_data; + double double_data; + ulong length[7]; + my_bool is_null[7]; + MYSQL_BIND my_bind[7]; + int rc; + int i; + + myheader("test_wl4166"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS table_4166"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE table_4166(col1 tinyint NOT NULL, " + "col2 varchar(15), col3 int, " + "col4 smallint, col5 bigint, " + "col6 float, col7 double, " + "colX varchar(10) default NULL)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO table_4166(col1, col2, col3, col4, col5, col6, col7) " + "VALUES(?, ?, ?, ?, ?, ?, ?)"); + check_stmt(stmt); + + verify_param_count(stmt, 7); + + bzero(my_bind, sizeof(my_bind)); + /* tinyint */ + my_bind[0].buffer_type= MYSQL_TYPE_TINY; + my_bind[0].buffer= (void *)&tiny_data; + /* string */ + my_bind[1].buffer_type= MYSQL_TYPE_STRING; + my_bind[1].buffer= (void *)str_data; + my_bind[1].buffer_length= 1000; /* Max string length */ + /* integer */ + my_bind[2].buffer_type= MYSQL_TYPE_LONG; + my_bind[2].buffer= (void *)&int_data; + /* short */ + my_bind[3].buffer_type= MYSQL_TYPE_SHORT; + my_bind[3].buffer= (void *)&small_data; + /* bigint */ + my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG; + my_bind[4].buffer= (void *)&big_data; + /* float */ + my_bind[5].buffer_type= MYSQL_TYPE_FLOAT; + my_bind[5].buffer= (void *)&real_data; + /* double */ + my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE; + my_bind[6].buffer= (void *)&double_data; + + for (i= 0; i < (int) array_elements(my_bind); i++) + { + my_bind[i].length= &length[i]; + my_bind[i].is_null= &is_null[i]; + is_null[i]= 0; + } + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + int_data= 320; + small_data= 1867; + big_data= 1000; + real_data= 2; + double_data= 6578.001; + + /* now, execute the prepared statement to insert 10 records.. */ + for (tiny_data= 0; tiny_data < 10; tiny_data++) + { + length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data)); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + int_data += 25; + small_data += 10; + big_data += 100; + real_data += 1; + double_data += 10.09; + } + + /* force a re-prepare with some DDL */ + + rc= mysql_query(mysql, + "ALTER TABLE table_4166 change colX colX varchar(20) default NULL"); + myquery(rc); + + /* + execute the prepared statement again, + without changing the types of parameters already bound. + */ + + for (tiny_data= 50; tiny_data < 60; tiny_data++) + { + length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data)); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + int_data += 25; + small_data += 10; + big_data += 100; + real_data += 1; + double_data += 10.09; + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE table_4166"); + myquery(rc); + +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -17689,6 +17807,7 @@ static struct my_tests_st my_tests[]= { { "test_bug31418", test_bug31418 }, { "test_bug31669", test_bug31669 }, { "test_bug28386", test_bug28386 }, + { "test_wl4166", test_wl4166 }, { 0, 0 } }; |