diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result index cca00dd4781..9e1db062368 100644 --- a/mysql-test/r/ps_ddl.result +++ b/mysql-test/r/ps_ddl.result @@ -35,6 +35,7 @@ Part 3: NOTHING -> VIEW transitions ===================================================================== Part 4: TABLE -> NOTHING transitions ===================================================================== +# Test 4-a: select ... from create table t1 (a int); prepare stmt from "select * from t1"; execute stmt; @@ -59,6 +60,32 @@ 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; ===================================================================== Part 5: TABLE -> TABLE (DDL) transitions ===================================================================== @@ -445,6 +472,7 @@ deallocate prepare stmt; ===================================================================== Part 8: TABLE -> TEMPORARY TABLE transitions ===================================================================== +# Test 8-a: base table used recreated as temporary table create table t1 (a int); prepare stmt from "select * from t1"; execute stmt; @@ -463,6 +491,37 @@ 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; ===================================================================== Part 9: TABLE -> VIEW transitions ===================================================================== @@ -504,6 +563,7 @@ deallocate prepare stmt; ===================================================================== Part 11: TEMPORARY TABLE -> TABLE transitions ===================================================================== +# 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); @@ -525,6 +585,38 @@ a 1 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; ===================================================================== Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions ===================================================================== @@ -1505,11 +1597,11 @@ deallocate prepare stmt_sp; Ensure that metadata validation is performed for every type of SQL statement where it is needed. ===================================================================== -drop table if exists t1; -create table t1 (a int); # # 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); @@ -1568,6 +1660,18 @@ 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; @@ -1582,6 +1686,18 @@ 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 @@ -1636,6 +1752,56 @@ 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; 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() + 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() + 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/t/ps_ddl.test b/mysql-test/t/ps_ddl.test index 810dc568eee..e19e73df3ac 100644 --- a/mysql-test/t/ps_ddl.test +++ b/mysql-test/t/ps_ddl.test @@ -104,6 +104,7 @@ prepare stmt from "select * from t1"; --echo Part 4: TABLE -> NOTHING transitions --echo ===================================================================== +--echo # Test 4-a: select ... from
create table t1 (a int); prepare stmt from "select * from t1"; @@ -121,6 +122,25 @@ execute stmt; call p_verify_reprepare_count(0); deallocate prepare stmt; +--echo # Test 4-b: TABLE -> NOTHING by renaming the table +create table t1 (a int); +prepare stmt from "select * from t1"; +execute stmt; +call p_verify_reprepare_count(0); +execute stmt; +call p_verify_reprepare_count(0); + +rename table t1 to t2; +--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; +drop table t2; + --echo ===================================================================== --echo Part 5: TABLE -> TABLE (DDL) transitions --echo ===================================================================== @@ -143,11 +163,11 @@ call p_verify_reprepare_count(0); drop table t1; deallocate prepare stmt; + --echo ===================================================================== --echo Part 6: TABLE -> TABLE (TRIGGER) transitions --echo ===================================================================== - --echo # Test 6-a: adding a relevant trigger create table t1 (a int); @@ -414,6 +434,7 @@ deallocate prepare stmt; --echo Part 8: TABLE -> TEMPORARY TABLE transitions --echo ===================================================================== +--echo # Test 8-a: base table used recreated as temporary table create table t1 (a int); prepare stmt from "select * from t1"; @@ -430,6 +451,25 @@ call p_verify_reprepare_count(0); drop table t1; deallocate prepare stmt; +--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); + +create temporary table t1 AS SELECT 1; +execute stmt; +call p_verify_reprepare_count(1); +execute stmt; +call p_verify_reprepare_count(0); + +deallocate prepare stmt; +drop temporary table t1; +drop table t1; + + --echo ===================================================================== --echo Part 9: TABLE -> VIEW transitions --echo ===================================================================== @@ -471,6 +511,7 @@ deallocate prepare stmt; --echo Part 11: TEMPORARY TABLE -> TABLE transitions --echo ===================================================================== +--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); @@ -488,6 +529,27 @@ select * from t1; drop table t1; deallocate prepare stmt; + +--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; +call p_verify_reprepare_count(0); +execute stmt; +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; + + --echo ===================================================================== --echo Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions --echo ===================================================================== @@ -1354,13 +1416,15 @@ deallocate prepare stmt_sp; --echo Ensure that metadata validation is performed for every type of --echo SQL statement where it is needed. --echo ===================================================================== + +--echo # +--echo # SQLCOM_SELECT +--echo # + --disable_warnings drop table if exists t1; --enable_warnings create table t1 (a int); ---echo # ---echo # SQLCOM_SELECT ---echo # prepare stmt from "select 1 as res from dual where (1) in (select * from t1)"; drop table t1; create table t1 (x int); @@ -1368,16 +1432,16 @@ execute stmt; drop table t1; deallocate prepare stmt; call p_verify_reprepare_count(1); + --echo # --echo # SQLCOM_CREATE_TABLE --echo # + --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; @@ -1385,6 +1449,7 @@ 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); @@ -1392,6 +1457,7 @@ call p_verify_reprepare_count(1); 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; @@ -1406,7 +1472,23 @@ 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 '/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); @@ -1415,6 +1497,14 @@ 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 @@ -1445,9 +1535,47 @@ 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; +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; + + --echo # --echo # SQLCOM_UPDATE --echo # 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 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) +# { +# +# }. +# 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() + 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() + 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