# This test file contains a collection of tests developed for # WL#4179 (Stored programs: validation of stored program statements). # # The main idea of the tests here is to check that a stored program # properly handles metadata changes of the objects being used by # the stored program. ########################################################################### ########################################################################### --echo --echo # --echo # WL#4179: Stored programs: validation of stored program statements. --echo # --echo ########################################################################### ########################################################################### --echo # The test case below demonstrates that meta-data changes are detected --echo # by triggers. SET sql_mode = 'NO_ENGINE_SUBSTITUTION'; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT); CREATE TABLE t3 (a INT); INSERT INTO t2 VALUES (11, 12), (21, 22); CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t1 SELECT * FROM t2; INSERT INTO t3 (a) VALUES (1); SELECT * FROM t1; SELECT * FROM t2; ALTER TABLE t1 ADD COLUMN c INT; ALTER TABLE t2 ADD COLUMN c INT; INSERT INTO t2 VALUES (31, 32, 33); INSERT INTO t3 (a) VALUES (2); SELECT * FROM t1; SELECT * FROM t2; DROP TABLE t1; DROP TABLE t2; DROP TABLE t3; ########################################################################### --echo --echo # Check that NEW/OLD rows work within triggers. --echo CREATE TABLE t1 (a INT); INSERT INTO t1(a) VALUES (1); delimiter |; CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW BEGIN SET @a = OLD.a; SET @b = NEW.a; SELECT OLD.a INTO @c; SELECT NEW.a INTO @d; SET NEW.a = NEW.a * 2; END| delimiter ;| UPDATE t1 SET a = a * 10; SELECT @a, @c, @b, @d; SELECT a FROM t1; DROP TABLE t1; ########################################################################### --echo CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); --echo --echo # 1.1 Check if added column into table is recognized correctly --echo # in a stored procedure. ALTER TABLE t1 ADD COLUMN b INT DEFAULT 0; CALL p1(); --echo --echo # 1.2 Check if dropped column is not appeared in SELECT query --echo # executed inside a stored procedure. ALTER TABLE t1 DROP COLUMN a; CALL p1(); --echo --echo # 1.3 Check if changed column is picked up properly. ALTER TABLE t1 CHANGE COLUMN b b VARCHAR(255) DEFAULT 'n/a'; DELETE FROM t1; INSERT INTO t1 VALUES (b), ('hello'); CALL p1(); --echo --echo # 1.4 Check if table's recreation is handled correctly --echo # inside a call of stored procedure. DROP TABLE t1; DROP PROCEDURE p1; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TABLE t1; --error ER_NO_SUCH_TABLE CALL p1(); CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CALL p1(); --echo --echo # 1.5 Recreate table t1 with another set of columns and --echo # re-call a stored procedure. DROP TABLE t1; DROP PROCEDURE p1; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TABLE t1; --error ER_NO_SUCH_TABLE CALL p1(); CREATE TABLE t1 (b VARCHAR(10), c VARCHAR(10)); INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); CALL p1(); DROP TABLE t1; DROP PROCEDURE p1; ########################################################################### --echo --echo # 2.1 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if some columns were added into the view --echo # definition by ALTER VIEW; CREATE VIEW v1 AS SELECT 1, 2, 3; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); ALTER VIEW v1 AS SELECT 1, 2, 3, 4, 5; CALL p1(); --echo --echo # 2.2 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if some columns were removed from the view --echo # definition by ALTER VIEW; ALTER VIEW v1 AS SELECT 1, 5; CALL p1(); --echo --echo # 2.3 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if a base table for the view being used was --echo # extended by new columns (by ALTER TABLE); CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); DROP VIEW v1; CREATE VIEW v1 AS SELECT * FROM t1; DROP PROCEDURE p1; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); ALTER TABLE t1 ADD COLUMN c INT DEFAULT 3; # NOTE: this behaviour differs from the one of regular tables -- the thing is # that "The view definition is “frozen” at creation time, so changes to the # underlying tables afterward do not affect the view definition." # (http://dev.mysql.com/doc/refman/5.0/en/create-view.html). # So, this call should return 2 (not 3) columns. CALL p1(); --echo --echo # 2.4 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if not used columns were removed from the --echo # base table of this view (by ALTER TABLE); DROP TABLE t1; CREATE TABLE t1(a INT, b INT, c INT); INSERT INTO t1 VALUES (1, 2, 3); DROP VIEW v1; CREATE VIEW v1 AS SELECT b, c FROM t1; DROP PROCEDURE p1; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); ALTER TABLE t1 DROP COLUMN a; CALL p1(); ALTER TABLE t1 DROP COLUMN b; # NOTE: see the note above about view specific. Must-have column has been # dropped -- the view has become invalid. --error ER_VIEW_INVALID CALL p1(); --echo --echo # 2.5 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if a type of some base table's columns were --echo # changed (by ALTER TABLE); DROP TABLE t1; CREATE TABLE t1(a INT, b INT, c INT); INSERT INTO t1 VALUES (1, 2, 3); DROP VIEW v1; CREATE VIEW v1 AS SELECT b, c FROM t1; DROP PROCEDURE p1; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); ALTER TABLE t1 CHANGE COLUMN b b VARCHAR(255) DEFAULT 'n/a'; DELETE FROM t1; INSERT INTO t1(a, c) VALUES (10, 30); CALL p1(); --echo --echo # 2.6 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if the view 'v' was dropped and created again --echo # with the same definition; --echo # --echo # 2.7 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if the view 'v' was dropped and created again --echo # with different, but compatible definition. DROP VIEW v1; DROP TABLE t1; DROP PROCEDURE p1; CREATE VIEW v1 AS SELECT 1, 2, 3; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); DROP VIEW v1; --error ER_NO_SUCH_TABLE CALL p1(); CREATE VIEW v1 AS SELECT 4, 5, 6; CALL p1(); --echo --echo # 2.8 Stored program that uses query like 'SELECT * FROM v' must be --echo # re-executed successfully if the view base tables have been re-created --echo # using the same or compatible definition. DROP VIEW v1; DROP PROCEDURE p1; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE VIEW v1 AS SELECT * FROM t1; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); DROP TABLE t1; --error ER_VIEW_INVALID CALL p1(); CREATE TABLE t1(a VARCHAR(255), b VARCHAR(255)); INSERT INTO t1 VALUES ('a', 'b'), ('c', 'd'); CALL p1(); DROP VIEW v1; DROP TABLE t1; DROP PROCEDURE p1; --echo --echo # 3.1 Stored program that uses query like 'SELECT * FROM t' must be --echo # re-executed successfully if some columns were added into temporary table --echo # table 't' (by ALTER TABLE); CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); ALTER TABLE t1 ADD COLUMN c INT DEFAULT 3; CALL p1(); --echo --echo # 3.2 Stored program that uses query like 'SELECT * FROM t' must be --echo # re-executed successfully if some columns were removed from temporary --echo # table 't' (by ALTER TABLE); ALTER TABLE t1 DROP COLUMN a; CALL p1(); --echo --echo # 3.3 Stored program that uses query like 'SELECT * FROM t' must be --echo # re-executed successfully if a type of some temporary table's columns were --echo # changed (by ALTER TABLE); ALTER TABLE t1 CHANGE COLUMN b b VARCHAR(255) DEFAULT 'n/a'; INSERT INTO t1(c) VALUES (4); CALL p1(); --echo --echo # 3.4 Stored program that uses query like 'SELECT * FROM t' must be --echo # re-executed successfully if the temporary table 't' was dropped and --echo # created again with the same definition; --echo # --echo # 3.5 Stored program that uses query like 'SELECT * FROM t' must be --echo # re-executed successfully if the temporary table 't' was dropped and --echo # created again with different, but compatible definition. DROP TEMPORARY TABLE t1; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CALL p1(); DROP TEMPORARY TABLE t1; CREATE TEMPORARY TABLE t1(a VARCHAR(255), b VARCHAR(255), c VARCHAR(255)); INSERT INTO t1 VALUES ('aa', 'bb', 'cc'); CALL p1(); DROP TEMPORARY TABLE t1; DROP PROCEDURE p1; ########################################################################### --echo --echo # 4.1 Stored program must fail when it is re-executed after a table's column --echo # that this program is referenced to has been removed; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT a, b FROM t1; CALL p1(); ALTER TABLE t1 DROP COLUMN b; --error ER_BAD_FIELD_ERROR CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; --echo --echo # 4.2 Stored program must fail when it is re-executed after a temporary --echo # table's column that this program is referenced to has been removed; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT a, b FROM t1; CALL p1(); ALTER TABLE t1 DROP COLUMN b; --error ER_BAD_FIELD_ERROR CALL p1(); DROP PROCEDURE p1; DROP TEMPORARY TABLE t1; --echo --echo # 4.3 Stored program must fail when it is re-executed after a view's --echo # column that this program is referenced to has been removed; CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b; CREATE PROCEDURE p1() SELECT a, b FROM v1; CALL p1(); ALTER VIEW v1 AS SELECT 1 AS a; --error ER_BAD_FIELD_ERROR CALL p1(); DROP PROCEDURE p1; DROP VIEW v1; --echo --echo # 4.4 Stored program must fail when it is re-executed after a regular table --echo # that this program referenced to was removed; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT a, b FROM t1; CALL p1(); DROP TABLE t1; --error ER_NO_SUCH_TABLE CALL p1(); DROP PROCEDURE p1; --echo --echo # 4.5 Stored program must fail when it is re-executed after a view that --echo # this program referenced to was removed; CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b; CREATE PROCEDURE p1() SELECT a, b FROM v1; CALL p1(); DROP VIEW v1; --error ER_NO_SUCH_TABLE CALL p1(); DROP PROCEDURE p1; --echo --echo # 4.6 Stored program must fail when it is re-executed after a temporary --echo # table that this program referenced to was removed; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT a, b FROM t1; CALL p1(); DROP TABLE t1; --error ER_NO_SUCH_TABLE CALL p1(); DROP PROCEDURE p1; --echo --echo # 4.7 Stored program must fail if the program executes some --echo # SQL-statement and afterwards re-executes it again when some table 't' --echo # referenced by the statement was dropped in the period between statement --echo # execution; CREATE TABLE t1(a INT); CREATE TABLE t2(a INT); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE CONTINUE HANDLER FOR 1146 SELECT 'Table t1 does not exist anymore' as msg; SELECT * FROM t1; INSERT INTO t2 VALUES (1); SELECT GET_LOCK('m1', 10000); SELECT * FROM t1; END| delimiter ;| --echo --echo # -- connection: con1 --connect (con1, localhost, root) SELECT GET_LOCK('m1', 0); --echo --echo # -- connection: default --connection default --send CALL p1() --echo --echo # -- connection: con1 --connection con1 let $wait_condition = SELECT COUNT(*) = 1 FROM t2; --source include/wait_condition.inc DROP TABLE t1; SELECT RELEASE_LOCK('m1'); --echo --echo # -- connection: default --connection default --reap --disconnect con1 DROP TABLE t2; DROP PROCEDURE p1; ########################################################################### --echo --echo # 5.1 Regular table -> View CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TABLE t1; CREATE VIEW t1 AS SELECT 1 AS a, 2 AS b; CALL p1(); DROP PROCEDURE p1; DROP VIEW t1; --echo --echo # 5.2 Regular table -> Temporary table CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TABLE t1; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CALL p1(); DROP PROCEDURE p1; DROP TEMPORARY TABLE t1; --echo --echo # 5.3 View -> Regular table CREATE VIEW t1 AS SELECT 1 AS a, 2 AS b; CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP VIEW t1; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; --echo --echo # 5.4 View -> Temporary table CREATE VIEW t1 AS SELECT 1 AS a, 2 AS b; CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP VIEW t1; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CALL p1(); DROP PROCEDURE p1; DROP TEMPORARY TABLE t1; --echo --echo # 5.5 Temporary table -> View CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TEMPORARY TABLE t1; CREATE VIEW t1 AS SELECT 1 AS a, 2 AS b; CALL p1(); DROP PROCEDURE p1; DROP VIEW t1; --echo --echo # 5.6 Temporary table -> Regular table CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); DROP TEMPORARY TABLE t1; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; ########################################################################### --echo --echo # 6.1 Trigger that uses column 'a' of table 't' via pseudo-variable NEW --echo # must be re-executed successfully if the table definition has been changed --echo # in a compatible way. "Compatible way" in this case is that if the table --echo # 't' still has a column named 'a' and the column type is compatible with --echo # the operation that NEW.a takes part of. --echo # --echo # 6.2 Trigger that uses column 'a' of table 't' via pseudo-variable OLD --echo # must be re-executed successfully if the table definition has been changed --echo # in a compatible way. "Compatible way" in this case is that if the table --echo # 't' still has a column named 'a' and the column type is compatible with --echo # the operation that OLD.a takes part of. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW BEGIN SET @x = OLD.a; SET @y = NEW.a; END| delimiter ;| --echo SET @x = 0, @y = 0; UPDATE t1 SET a = 3, b = 4; SELECT @x, @y; --echo ALTER TABLE t1 ADD COLUMN c INT DEFAULT -1; --echo SET @x = 0, @y = 0; UPDATE t1 SET a = 5, b = 6; SELECT @x, @y; --echo ALTER TABLE t1 CHANGE COLUMN a a VARCHAR(255); --echo SET @x = 0, @y = 0; UPDATE t1 SET a = CONCAT('xxx_', a), b = 7; SELECT @x, @y; --echo DROP TABLE t1; --echo --echo # 6.3 Re-execution of a trigger that uses column 'a' of table 't' via --echo # pseudo-variable NEW must fail if the table definition has been changed in --echo # the way that the column 'a' does not exist anymore. --echo # --echo # 6.4 Re-execution of a trigger that uses column 'a' of table 't' via --echo # pseudo-variable OLD must fail if the table definition has been changed in --echo # the way that the column 'a' does not exist anymore. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW BEGIN SET @x = OLD.a; SET @y = NEW.b; END| delimiter ;| --echo UPDATE t1 SET a = 3, b = 4; --echo ALTER TABLE t1 CHANGE COLUMN a a2 INT; --echo --error ER_BAD_FIELD_ERROR UPDATE t1 SET a2 = 5, b = 6; --echo ALTER TABLE t1 CHANGE COLUMN a2 a INT; ALTER TABLE t1 CHANGE COLUMN b b2 INT; --echo --error ER_BAD_FIELD_ERROR UPDATE t1 SET a = 5, b2 = 6; --echo DROP TABLE t1; ########################################################################### --echo --echo # 7.1 Setup: --echo # - stored program 'a', which alters regular table 't' in a compatible --echo # way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must be executed successfully. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() ALTER TABLE t1 ADD COLUMN c INT DEFAULT 3| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; --echo --echo # 7.2 Setup: --echo # - stored program 'a', which alters temporary table 't' in a compatible --echo # way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must be executed successfully. CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() ALTER TABLE t1 ADD COLUMN c INT DEFAULT 3| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TEMPORARY TABLE t1; --echo --echo # 7.3 Setup: --echo # - stored program 'a', which re-creates regular table 't' in a --echo # compatible way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must be executed successfully. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() BEGIN DROP TABLE t1; CREATE TABLE t1(a INT, b INT, c INT); INSERT INTO t1 VALUES (1, 2, 3); END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; --echo --echo # 7.4 Setup: --echo # - stored program 'a', which re-creates temporary table 't' in a --echo # compatible way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must be executed successfully. CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() BEGIN DROP TEMPORARY TABLE t1; CREATE TEMPORARY TABLE t1(a INT, b INT, c INT); INSERT INTO t1 VALUES (1, 2, 3); END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TEMPORARY TABLE t1; --echo --echo # 7.5 Setup: --echo # - stored program 'a', which re-creates view 'v' in a compatible way; --echo # - stored program 'b', which calls 'a' and uses 'v' before and after the --echo # call; --echo # Stored program 'b' must be executed successfully. CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b; delimiter |; CREATE PROCEDURE p1() BEGIN DROP VIEW v1; CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b, 3 AS c; END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM v1; CALL p1(); SELECT a, b FROM v1; END| delimiter ;| --echo CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP VIEW v1; --echo --echo # 7.6 Setup: --echo # - stored program 'a', which alters regular table 't' in an incompatible --echo # way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must fail on access to the table after its --echo # modification. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() ALTER TABLE t1 DROP COLUMN a| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo --error ER_BAD_FIELD_ERROR CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; --echo --echo # 7.7 Setup: --echo # - stored program 'a', which alters temporary table 't' in an --echo # incompatible way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must fail on access to the table after its --echo # modification. CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() ALTER TABLE t1 DROP COLUMN a| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo --error ER_BAD_FIELD_ERROR CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TEMPORARY TABLE t1; --echo --echo # 7.8 Setup: --echo # - stored program 'a', which re-creates regular table 't' in an --echo # incompatible way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must fail on access to the table after its --echo # modification. CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() BEGIN DROP TABLE t1; CREATE TABLE t1(b INT, c INT); INSERT INTO t1 VALUES (2, 3); END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo --error ER_BAD_FIELD_ERROR CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; --echo --echo # 7.9 Setup: --echo # - stored program 'a', which re-creates temporary table 't' in an --echo # incompatible way; --echo # - stored program 'b', which calls 'a' and uses 't' before and after the --echo # call; --echo # Stored program 'b' must fail on access to the table after its --echo # modification. CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); delimiter |; CREATE PROCEDURE p1() BEGIN DROP TEMPORARY TABLE t1; CREATE TEMPORARY TABLE t1(b INT, c INT); INSERT INTO t1 VALUES (2, 3); END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM t1; CALL p1(); SELECT a, b FROM t1; END| delimiter ;| --echo --error ER_BAD_FIELD_ERROR CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TEMPORARY TABLE t1; --echo --echo # 7.10 Setup: --echo # - stored program 'a', which re-creates view 'v' in an incompatible way; --echo # - stored program 'b', which calls 'a' and uses 'v' before and after the --echo # call; --echo # Stored program 'b' must fail on access to the view after its --echo # modification. CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b; delimiter |; CREATE PROCEDURE p1() BEGIN DROP VIEW v1; CREATE VIEW v1 AS SELECT 2 AS b, 3 AS c; END| CREATE PROCEDURE p2() BEGIN SELECT a, b FROM v1; CALL p1(); SELECT a, b FROM v1; END| delimiter ;| --echo --error ER_BAD_FIELD_ERROR CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP VIEW v1; ########################################################################### --echo # 8. Stored program must be executed successfully when: --echo # a. the program uses a table/view/temporary table that doesn't exist --echo # at the time of start program execution --echo # b. failed reference to the missed table/view/temporary table handled --echo # by stored program --echo # c. this table/view/temporary table is created as part of the --echo # program execution --echo # d. stored program gets access to newly created table/view/temporary --echo # table from some SQL-statement during subsequent stored program execution. delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SELECT 'SQLEXCEPTION caught' AS msg; CREATE TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); END; SELECT * FROM t1; SELECT * FROM t1; DROP TABLE t1; END| CREATE PROCEDURE p2() BEGIN DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SELECT 'SQLEXCEPTION caught' AS msg; CREATE TEMPORARY TABLE t1(a INT, b INT); INSERT INTO t1 VALUES (1, 2); END; SELECT * FROM t1; SELECT * FROM t1; DROP TEMPORARY TABLE t1; END| CREATE PROCEDURE p3() BEGIN DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN SELECT 'SQLEXCEPTION caught' AS msg; CREATE VIEW v1 AS SELECT 1 AS a, 2 AS b; END; SELECT * FROM v1; SELECT * FROM v1; DROP VIEW v1; END| delimiter ;| CALL p1(); CALL p2(); CALL p3(); DROP PROCEDURE p1; DROP PROCEDURE p2; DROP PROCEDURE p3; ########################################################################### --echo --echo # 9. Stored program must be executed successfully when --echo # - the stored program has an expression in one of the following --echo # statements --echo # - RETURN --echo # - IF --echo # - CASE --echo # - WHILE --echo # - UNTIL --echo # - SET --echo # - the expression depends on the meta-data of some table/view/temporary table; --echo # - the meta-data of dependent object has changed in a compatible way. --echo # --echo # Note, that CASE-expression must be evaluated once even if (some) --echo # CASE-expressions need to be re-parsed. --echo # --echo # 10. Subsequent executions of a stored program must fail when --echo # - the stored program has an expression in one of the following --echo # statements --echo # - RETURN --echo # - IF --echo # - CASE --echo # - WHILE --echo # - UNTIL --echo # - SET --echo # - the expression depends on the meta-data of some table/view/temporary table; --echo # - the meta-data of dependent object has changed in a non-compatible way. --echo # --echo # Note, that CASE-expression must be evaluated once even if (some) --echo # CASE-expressions need to be re-parsed. ########################################################################### --echo --echo # Check IF-statement. --echo delimiter |; # NOTE: check also that spaces (no spaces) don't matter. CREATE PROCEDURE p1() BEGIN IF(SELECT * FROM t1)THEN SELECT 1; ELSE SELECT 2; END IF; END| CREATE PROCEDURE p2() BEGIN DECLARE v INT DEFAULT 1; IF v * (SELECT * FROM t1) THEN SELECT 1; ELSE SELECT 2; END IF; END| CREATE FUNCTION f1() RETURNS INT BEGIN IF (SELECT * FROM t1) THEN RETURN 1; ELSE RETURN 2; END IF; RETURN 3; END| CREATE FUNCTION f2() RETURNS INT BEGIN DECLARE v INT DEFAULT 1; IF v * (SELECT * FROM t1) THEN RETURN 1; ELSE RETURN 2; END IF; RETURN 3; END| delimiter ;| CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); --echo CALL p1(); CALL p2(); SELECT f1(); SELECT f2(); --echo UPDATE t1 SET a = 0; --echo CALL p1(); CALL p2(); SELECT f1(); SELECT f2(); --echo ALTER TABLE t1 ADD COLUMN b INT DEFAULT 1; --echo --error ER_OPERAND_COLUMNS CALL p1(); --error ER_OPERAND_COLUMNS CALL p2(); --error ER_OPERAND_COLUMNS SELECT f1(); --error ER_OPERAND_COLUMNS SELECT f2(); --echo ALTER TABLE t1 DROP COLUMN a; --echo CALL p1(); CALL p2(); SELECT f1(); SELECT f2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP FUNCTION f1; DROP FUNCTION f2; DROP TABLE t1; ########################################################################### --echo --echo # Check WHILE-statement. --echo delimiter |; # NOTE: check also that spaces (no spaces) don't matter. CREATE PROCEDURE p1(x INT) BEGIN WHILE(SELECT * FROM t1)DO SELECT x; UPDATE t1 SET a = x; SET x = x - 1; END WHILE; END| delimiter ;| CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (0); CALL p1(3); UPDATE t1 SET a = 1; CALL p1(3); UPDATE t1 SET a = 1; ALTER TABLE t1 ADD COLUMN b INT DEFAULT 1; --error ER_OPERAND_COLUMNS CALL p1(3); ALTER TABLE t1 DROP COLUMN a; # Column 'a' not found for the UPDATE statememnt. --error ER_BAD_FIELD_ERROR CALL p1(3); DROP PROCEDURE p1; DROP TABLE t1; ########################################################################### --echo --echo # Check REPEAT-statement. --echo delimiter |; # NOTE: check also that spaces (no spaces) don't matter. CREATE PROCEDURE p1(x INT) BEGIN REPEAT SELECT x; UPDATE t1 SET a = x; SET x = x - 1; UNTIL(NOT (SELECT * FROM t1))END REPEAT; END| delimiter ;| CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (0); CALL p1(3); UPDATE t1 SET a = 1; CALL p1(3); UPDATE t1 SET a = 1; ALTER TABLE t1 ADD COLUMN b INT DEFAULT 1; --error ER_OPERAND_COLUMNS CALL p1(3); ALTER TABLE t1 DROP COLUMN a; # Column 'a' not found for the UPDATE statememnt. --error ER_BAD_FIELD_ERROR CALL p1(3); DROP PROCEDURE p1; DROP TABLE t1; ########################################################################### --echo --echo # Check CASE-statement (round #1). --echo delimiter |; # Check that metadata changes in WHEN-expressions are handled properly. CREATE PROCEDURE p1() BEGIN CASE WHEN (SELECT * FROM t1) = 1 THEN SELECT 'a1'; WHEN (SELECT * FROM t1) = 2 THEN SELECT 'a2'; WHEN (SELECT * FROM t1) = 3 THEN SELECT 'a3'; ELSE SELECT 'a4'; END CASE; END| # Check that metadata changes in CASE-expression, are handled properly. CREATE PROCEDURE p2() BEGIN CASE (SELECT * FROM t1) WHEN 1 THEN SELECT 'a1'; WHEN 2 THEN SELECT 'a2'; WHEN 3 THEN SELECT 'a3'; ELSE SELECT 'a4'; END CASE; END| delimiter ;| CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (0); --echo CALL p1(); CALL p2(); --echo UPDATE t1 SET a = 3; --echo CALL p1(); CALL p2(); --echo ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; --echo --error ER_OPERAND_COLUMNS CALL p1(); --error ER_OPERAND_COLUMNS CALL p2(); --echo ALTER TABLE t1 DROP COLUMN a; --echo CALL p1(); CALL p2(); --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; ########################################################################### --echo --echo # Check CASE-statement (round #2). --echo # --echo # Check that CASE-expression is executed once even if the metadata, used --echo # in a WHEN-expression, have changed. --echo CREATE TABLE t1(a INT); CREATE TABLE t2(a INT); INSERT INTO t1 VALUES (1); INSERT INTO t2 VALUES (1); delimiter |; CREATE FUNCTION f1() RETURNS INT BEGIN SET @x = @x + 1; RETURN (SELECT a FROM t1); END| CREATE PROCEDURE p1() BEGIN CASE f1() WHEN 1 THEN SELECT 'a1'; WHEN 2 THEN SELECT 'a2'; WHEN (SELECT * FROM t2) THEN SELECT 'subselect'; ELSE SELECT 'else'; END CASE; END| delimiter ;| --echo SET @x = 0; CALL p1(); SELECT @x; --echo UPDATE t1 SET a = 3; ALTER TABLE t2 ADD COLUMN b INT DEFAULT 3; --echo SET @x = 0; --error ER_OPERAND_COLUMNS CALL p1(); SELECT @x; --echo ALTER TABLE t2 DROP COLUMN a; --echo SET @x = 0; CALL p1(); SELECT @x; --echo DROP PROCEDURE p1; DROP FUNCTION f1; DROP TABLE t1; DROP TABLE t2; ########################################################################### --echo --echo # Check DEFAULT clause. --echo # --echo CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE v INT DEFAULT (SELECT * FROM t1); SELECT v; END| delimiter ;| --echo CALL p1(); --echo ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; --echo --error ER_OPERAND_COLUMNS CALL p1(); --echo ALTER TABLE t1 DROP COLUMN a; --echo CALL p1(); --echo DROP PROCEDURE p1; DROP TABLE t1; ########################################################################### --echo --echo # Check SET. --echo # --echo CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); CREATE TABLE t2(a INT); INSERT INTO t2 VALUES (1); delimiter |; # Check SET for SP-variable. CREATE PROCEDURE p1() BEGIN DECLARE x INT; SET x = (SELECT * FROM t1); SELECT x; END| # Check SET for user variable. CREATE PROCEDURE p2() BEGIN SET @x = NULL; SET @x = (SELECT * FROM t1); SELECT @x; END| # Check SET for triggers. CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 FOR EACH ROW BEGIN SET NEW.a = (SELECT * FROM t1) * 2; END| delimiter ;| --echo CALL p1(); --echo CALL p2(); --echo UPDATE t2 SET a = 10; --echo ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; --echo --error ER_OPERAND_COLUMNS CALL p1(); --echo --error ER_OPERAND_COLUMNS CALL p2(); --echo --error ER_OPERAND_COLUMNS UPDATE t2 SET a = 20; --echo ALTER TABLE t1 DROP COLUMN a; --echo CALL p1(); --echo CALL p2(); --echo UPDATE t2 SET a = 30; --echo DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1; DROP TABLE t2; ########################################################################### --echo --echo # 11.1 If metadata of the objects (regular tables, temporary tables, --echo # views), used in SELECT-statement changed between DECLARE CURSOR and --echo # OPEN statements, the SELECT-statement should be re-parsed to use --echo # up-to-date metadata. --echo --echo --echo # - Regular table. --echo CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE v INT; DECLARE c CURSOR FOR SELECT * FROM t1; ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; ALTER TABLE t1 DROP COLUMN a; OPEN c; FETCH c INTO v; CLOSE c; SELECT v; END| delimiter ;| --echo CALL p1(); --echo DROP TABLE t1; DROP PROCEDURE p1; --echo --echo # - Temporary table. --echo CREATE TEMPORARY TABLE t1(a INT); INSERT INTO t1 VALUES (1); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE v INT; DECLARE c CURSOR FOR SELECT * FROM t1; ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; ALTER TABLE t1 DROP COLUMN a; OPEN c; FETCH c INTO v; CLOSE c; SELECT v; END| delimiter ;| --echo CALL p1(); --echo DROP TEMPORARY TABLE t1; DROP PROCEDURE p1; # NOTE: ALTER VIEW is not available within Stored Programs. --echo --echo # 11.2 If the metadata changed between OPEN and FETCH or CLOSE --echo # statements, those changes should not be noticed. --echo CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE v INT; DECLARE c CURSOR FOR SELECT * FROM t1; OPEN c; ALTER TABLE t1 ADD COLUMN b INT DEFAULT 2; ALTER TABLE t1 DROP COLUMN a; FETCH c INTO v; CLOSE c; SELECT v; END| delimiter ;| --echo CALL p1(); --echo DROP TABLE t1; DROP PROCEDURE p1; --echo --echo # 11.3 Re-parsing of the SELECT-statement should be made correctly --echo # (in the correct parsing context) if the metadata changed between --echo # DECLARE CURSOR and OPEN statements, and those statements reside in different --echo # parsing contexts. --echo CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); delimiter |; CREATE PROCEDURE p1() BEGIN DECLARE f1 INT; DECLARE f2 INT; DECLARE f3 INT; DECLARE x INT DEFAULT 1; DECLARE y INT DEFAULT 2; DECLARE c CURSOR FOR SELECT x, y, t1.a FROM t1; ALTER TABLE t1 ADD COLUMN b INT; BEGIN DECLARE x INT DEFAULT 10; DECLARE y INT DEFAULT 20; OPEN c; FETCH c INTO f1, f2, f3; SELECT f1, f2, f3; CLOSE c; END; END| delimiter ;| --echo CALL p1(); --echo DROP TABLE t1; DROP PROCEDURE p1; ########################################################################### ## Other tests. ########################################################################### --echo --echo # Test procedure behaviour after view recreation. CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE VIEW v1 AS SELECT * FROM t1; CREATE PROCEDURE p1() SELECT * FROM v1; CALL p1(); --echo # Alter underlying table and recreate the view. ALTER TABLE t1 ADD COLUMN (b INT); ALTER VIEW v1 AS SELECT * FROM t1; --echo # And check whether the call of stored procedure handles it correctly. CALL p1(); DROP VIEW v1; DROP TABLE t1; DROP PROCEDURE p1; --echo # Test if metadata changes for temporary table is handled --echo # correctly inside a stored procedure. CREATE TEMPORARY TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE PROCEDURE p1() SELECT * FROM t1; CALL p1(); --echo # Test if added temporary table's column is recognized during --echo # procedure invocation. ALTER TABLE t1 ADD COLUMN (b INT); CALL p1(); --echo # Test if dropped temporary table's column is not appeared --echo # in procedure's result. ALTER TABLE t1 DROP COLUMN a; CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; --echo # Test handle of metadata changes with stored function. CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); delimiter |; CREATE FUNCTION f1() RETURNS INT BEGIN CREATE TEMPORARY TABLE t1_result_set AS SELECT * FROM t1; RETURN 0; END| delimiter ;| SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; --echo # Check if added column is noticed by invocation of stored function. ALTER TABLE t1 ADD COLUMN (b INT); SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; --echo # Check if dropped column is noticed by invocation of stored function. ALTER TABLE t1 DROP COLUMN a; SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP TABLE t1; DROP FUNCTION f1; --echo # Test if table's recreation is handled correctly --echo # inside a stored function. CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); delimiter |; CREATE FUNCTION f1() RETURNS INT BEGIN CREATE TEMPORARY TABLE t1_result_set AS SELECT * FROM t1; RETURN 0; END| delimiter ;| SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; --echo # Recreate table and check if it is handled correctly --echo # by function invocation. DROP TABLE t1; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP FUNCTION f1; DROP TABLE t1; --echo # Test if changes in the view's metadata is handled --echo # correctly by function call. CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CREATE VIEW v1 AS SELECT * FROM t1; delimiter |; CREATE FUNCTION f1() RETURNS INT BEGIN CREATE TEMPORARY TABLE t1_result_set AS SELECT * FROM v1; RETURN 0; END| delimiter ;| SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; ALTER TABLE t1 ADD COLUMN (b INT); ALTER VIEW v1 AS SELECT * FROM t1; SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP TABLE t1; DROP VIEW v1; DROP FUNCTION f1; --echo # Check if queried object's type substitution (table->view, view->table, --echo # table->temp table, etc.) is handled correctly during invocation of --echo # stored function/procedure. CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); delimiter |; CREATE FUNCTION f1() RETURNS INT BEGIN CREATE TEMPORARY TABLE t1_result_set AS SELECT * FROM t1; RETURN 0; END| CREATE PROCEDURE p1() SELECT * FROM t1| delimiter ;| CALL p1(); SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP TABLE t1; CREATE TEMPORARY TABLE t1 (a INT); INSERT INTO t1 VALUES (1), (2); CALL p1; SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP TABLE t1; CREATE TABLE t2 (a INT); INSERT INTO t2 VALUES (1), (2); CREATE VIEW t1 AS SELECT * FROM t2; CALL p1; SELECT f1(); SELECT * FROM t1_result_set; DROP TABLE t1_result_set; DROP TABLE t2; DROP VIEW t1; DROP FUNCTION f1; DROP PROCEDURE p1; --echo # Test handle of metadata changes with triggers. CREATE TABLE t1 (a INT); CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET new.a = new.a + 100; INSERT INTO t1 VALUES (1), (2); SELECT * FROM t1; --echo # Check if added table's column is handled correctly inside trigger. ALTER TABLE t1 ADD COLUMN (b INT); INSERT INTO t1 VALUES (3, 4); SELECT * FROM t1; DROP TRIGGER trg1; DROP TABLE t1; --echo # Test if deleted column is handled correctly by trigger invocation. CREATE TABLE t1 (a INT, b INT); CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET new.a = new.a + 100; INSERT INTO t1 VALUES (1, 2), (3, 4); SELECT * FROM t1; ALTER TABLE t1 DROP COLUMN b; INSERT INTO t1 VALUES (5); SELECT * FROM t1; DROP TRIGGER trg1; DROP TABLE t1; --echo # Check if server returns and error when was dropped a column --echo # that is used inside a trigger body. CREATE TABLE t1 (a INT, b INT); CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET new.a = new.a + 100; INSERT INTO t1 VALUES (1, 2), (3, 4); SELECT * FROM t1; ALTER TABLE t1 DROP COLUMN a; --error ER_BAD_FIELD_ERROR INSERT INTO t1 VALUES (5); DROP TRIGGER trg1; DROP TABLE t1; --echo --echo # Check updateable views inside triggers. CREATE TABLE t1(a INT); INSERT INTO t1 VALUES (1); CREATE TABLE t2(a INT); INSERT INTO t2 VALUES (1); CREATE VIEW v1 AS SELECT a FROM t1; delimiter |; CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 FOR EACH ROW BEGIN INSERT INTO v1 VALUES (NEW.a); SET @x = (SELECT CHARSET(a) FROM v1 LIMIT 1); END| delimiter ;| --echo SET @x = NULL; UPDATE t2 SET a = 10; SELECT * FROM v1; SELECT @x; --echo ALTER TABLE t1 CHANGE COLUMN a a CHAR(2); --echo SET @x = NULL; UPDATE t2 SET a = 20; SELECT * FROM v1; SELECT @x; --echo DROP TABLE t1; DROP TABLE t2; DROP VIEW v1; SET sql_mode = default;