summaryrefslogtreecommitdiff
path: root/mysql-test/r/sp-error.result
diff options
context:
space:
mode:
authorunknown <malff/marcsql@weblab.(none)>2007-03-05 19:42:07 -0700
committerunknown <malff/marcsql@weblab.(none)>2007-03-05 19:42:07 -0700
commit266a7fff520eb2253226158df236865f2ad16ffe (patch)
treef4c20741942392a845ac21a035b1ea19c29a9579 /mysql-test/r/sp-error.result
parent74ac969d572848e98550f0e3c62864a03b5f1951 (diff)
downloadmariadb-git-266a7fff520eb2253226158df236865f2ad16ffe.tar.gz
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail) Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02') Bug 21825 (Incorrect message error deleting records in a table with a trigger for inserting) Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency error) Bug 25345 (Cursors from Functions) This fix resolves a long standing issue originally reported with bug 8407, which affect the behavior of Stored Procedures, Stored Functions and Trigger in many different ways, causing symptoms reported by all the bugs listed. In all cases, the root cause of the problem traces back to 8407 and how the server locks tables involved with sub statements. Prior to this fix, the implementation of stored routines would: - compute the transitive closure of all the tables referenced by a top level statement - open and lock all the tables involved - execute the top level statement "transitive closure of tables" means collecting: - all the tables, - all the stored functions, - all the views, - all the table triggers - all the stored procedures involved, and recursively inspect these objects definition to find more references to more objects, until the list of every object referenced does not grow any more. This mechanism is known as "pre-locking" tables before execution. The motivation for locking all the tables (possibly) used at once is to prevent dead locks. One problem with this approach is that, if the execution path the code really takes during runtime does not use a given table, and if the table is missing, the server would not execute the statement. This in particular has a major impact on triggers, since a missing table referenced by an update/delete trigger would prevent an insert trigger to run. Another problem is that stored routines might define SQL exception handlers to deal with missing tables, but the server implementation would never give user code a chance to execute this logic, since the routine is never executed when a missing table cause the pre-locking code to fail. With this fix, the internal implementation of the pre-locking code has been relaxed of some constraints, so that failure to open a table does not necessarily prevent execution of a stored routine. In particular, the pre-locking mechanism is now behaving as follows: 1) the first step, to compute the transitive closure of all the tables possibly referenced by a statement, is unchanged. 2) the next step, which is to open all the tables involved, only attempts to open the tables added by the pre-locking code, but silently fails without reporting any error or invoking any exception handler is the table is not present. This is achieved by trapping internal errors with Prelock_error_handler 3) the locking step only locks tables that were successfully opened. 4) when executing sub statements, the list of tables used by each statements is evaluated as before. The tables needed by the sub statement are expected to be already opened and locked. Statement referencing tables that were not opened in step 2) will fail to find the table in the open list, and only at this point will execution of the user code fail. 5) when a runtime exception is raised at 4), the instruction continuation destination (the next instruction to execute in case of SQL continue handlers) is evaluated. This is achieved with sp_instr::exec_open_and_lock_tables() 6) if a user exception handler is present in the stored routine, that handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be trapped by stored routines. If no handler exists, then the runtime execution will fail as expected. With all these changes, a side effect is that view security is impacted, in two different ways. First, a view defined as "select stored_function()", where the stored function references a table that may not exist, is considered valid. The rationale is that, because the stored function might trap exceptions during execution and still return a valid result, there is no way to decide when the view is created if a missing table really cause the view to be invalid. Secondly, testing for existence of tables is now done later during execution. View security, which consist of trapping errors and return a generic ER_VIEW_INVALID (to prevent disclosing information) was only implemented at very specific phases covering *opening* tables, but not covering the runtime execution. Because of this existing limitation, errors that were previously trapped and converted into ER_VIEW_INVALID are not trapped, causing table names to be reported to the user. This change is exposing an existing problem, which is independent and will be resolved separately. mysql-test/r/information_schema_db.result: Revised the pre-locking code implementation, aligned the tests. mysql-test/r/sp-error.result: Revised the pre-locking code implementation, aligned the tests. mysql-test/r/sp.result: Revised the pre-locking code implementation, aligned the tests. mysql-test/r/trigger.result: Revised the pre-locking code implementation, aligned the tests. mysql-test/r/view.result: Revised the pre-locking code implementation, aligned the tests. mysql-test/t/sp-error.test: Revised the pre-locking code implementation, aligned the tests. mysql-test/t/sp.test: Revised the pre-locking code implementation, aligned the tests. mysql-test/t/trigger.test: Revised the pre-locking code implementation, aligned the tests. sql/lock.cc: table->placeholder now checks for schema_table sql/mysqld.cc: my_message_sql(): invoke internal exception handlers sql/sp_head.cc: exec_open_and_lock_tables(): open and lock tables, or return the continuation destination of this instruction sql/sp_head.h: exec_open_and_lock_tables(): open and lock tables, or return the continuation destination of this instruction sql/sql_base.cc: Prelock_error_handler: delay open table errors until execution sql/sql_class.cc: THD: add internal error handler, as an exception mechanism. sql/sql_class.h: THD: add internal error handler, as an exception mechanism. sql/sql_update.cc: table->placeholder now checks for schema_table sql/table.cc: st_table_list::hide_view_error(): masked more errors for view security sql/table.h: table->placeholder now checks for schema_table, and unopened tables
Diffstat (limited to 'mysql-test/r/sp-error.result')
-rw-r--r--mysql-test/r/sp-error.result143
1 files changed, 137 insertions, 6 deletions
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index e7e387f4348..332d4fa4519 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1128,9 +1128,9 @@ drop view if exists v1, v2, v3, v4;
create function bug11555_1() returns int return (select max(i) from t1);
create function bug11555_2() returns int return bug11555_1();
create view v1 as select bug11555_1();
-ERROR 42S02: Table 'test.t1' doesn't exist
+drop view v1;
create view v2 as select bug11555_2();
-ERROR 42S02: Table 'test.t1' doesn't exist
+drop view v2;
create table t1 (i int);
create view v1 as select bug11555_1();
create view v2 as select bug11555_2();
@@ -1143,8 +1143,7 @@ ERROR HY000: View 'test.v2' references invalid table(s) or column(s) or function
select * from v3;
ERROR HY000: View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
create view v4 as select * from v1;
-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
-drop view v1, v2, v3;
+drop view v1, v2, v3, v4;
drop function bug11555_1;
drop function bug11555_2;
create table t1 (i int);
@@ -1153,12 +1152,12 @@ create trigger t1_ai after insert on t1 for each row insert into t2 values (new.
create view v1 as select * from t1;
drop table t2;
insert into v1 values (1);
-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
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
drop trigger t1_ai;
create function bug11555_1() returns int return (select max(i) from t2);
create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
insert into v1 values (2);
-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
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
drop function bug11555_1;
drop table t1;
drop view v1;
@@ -1269,3 +1268,135 @@ call bug24491();
ERROR 42S22: Unknown column 'y.value' in 'field list'
drop procedure bug24491;
drop tables t1;
+DROP FUNCTION IF EXISTS bug18914_f1;
+DROP FUNCTION IF EXISTS bug18914_f2;
+DROP PROCEDURE IF EXISTS bug18914_p1;
+DROP PROCEDURE IF EXISTS bug18914_p2;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (i INT);
+CREATE PROCEDURE bug18914_p1() CREATE TABLE t2 (i INT);
+CREATE PROCEDURE bug18914_p2() DROP TABLE IF EXISTS no_such_table;
+CREATE FUNCTION bug18914_f1() RETURNS INT
+BEGIN
+CALL bug18914_p1();
+RETURN 1;
+END |
+CREATE FUNCTION bug18914_f2() RETURNS INT
+BEGIN
+CALL bug18914_p2();
+RETURN 1;
+END |
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+CALL bug18914_p1();
+INSERT INTO t1 VALUES (1);
+ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
+SELECT bug18914_f1();
+ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
+SELECT bug18914_f2();
+ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
+SELECT * FROM t2;
+ERROR 42S02: Table 'test.t2' doesn't exist
+DROP FUNCTION bug18914_f1;
+DROP FUNCTION bug18914_f2;
+DROP PROCEDURE bug18914_p1;
+DROP PROCEDURE bug18914_p2;
+DROP TABLE t1;
+drop table if exists bogus_table_20713;
+drop function if exists func_20713_a;
+drop function if exists func_20713_b;
+create table bogus_table_20713( id int(10) not null primary key);
+insert into bogus_table_20713 values (1), (2), (3);
+create function func_20713_a() returns int(11)
+begin
+declare id int;
+declare continue handler for sqlexception set id=null;
+set @in_func := 1;
+set id = (select id from bogus_table_20713 where id = 3);
+set @in_func := 2;
+return id;
+end//
+create function func_20713_b() returns int(11)
+begin
+declare id int;
+declare continue handler for sqlstate value '42S02' set id=null;
+set @in_func := 1;
+set id = (select id from bogus_table_20713 where id = 3);
+set @in_func := 2;
+return id;
+end//
+set @in_func := 0;
+select func_20713_a();
+func_20713_a()
+NULL
+select @in_func;
+@in_func
+2
+set @in_func := 0;
+select func_20713_b();
+func_20713_b()
+NULL
+select @in_func;
+@in_func
+2
+drop table bogus_table_20713;
+set @in_func := 0;
+select func_20713_a();
+func_20713_a()
+NULL
+select @in_func;
+@in_func
+2
+set @in_func := 0;
+select func_20713_b();
+func_20713_b()
+NULL
+select @in_func;
+@in_func
+2
+drop function if exists func_20713_a;
+drop function if exists func_20713_b;
+drop table if exists table_25345_a;
+drop table if exists table_25345_b;
+drop procedure if exists proc_25345;
+drop function if exists func_25345;
+drop function if exists func_25345_b;
+create table table_25345_a (a int);
+create table table_25345_b (b int);
+create procedure proc_25345()
+begin
+declare c1 cursor for select a from table_25345_a;
+declare c2 cursor for select b from table_25345_b;
+select 1 as result;
+end ||
+create function func_25345() returns int(11)
+begin
+call proc_25345();
+return 1;
+end ||
+create function func_25345_b() returns int(11)
+begin
+declare c1 cursor for select a from table_25345_a;
+declare c2 cursor for select b from table_25345_b;
+return 1;
+end ||
+call proc_25345();
+result
+1
+select func_25345();
+ERROR 0A000: Not allowed to return a result set from a function
+select func_25345_b();
+func_25345_b()
+1
+drop table table_25345_a;
+call proc_25345();
+result
+1
+select func_25345();
+ERROR 0A000: Not allowed to return a result set from a function
+select func_25345_b();
+func_25345_b()
+1
+drop table table_25345_b;
+drop procedure proc_25345;
+drop function func_25345;
+drop function func_25345_b;