mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
6b2f13098a
according to the standard. The idea is to use Field-classes to implement stored routines variables. Also, we should provide facade to Item-hierarchy by Item_field class (it is necessary, since SRVs take part in expressions). The patch fixes the following bugs: - BUG#8702: Stored Procedures: No Error/Warning shown for inappropriate data type matching; - BUG#8768: Functions: For any unsigned data type, -ve values can be passed and returned; - BUG#8769: Functions: For Int datatypes, out of range values can be passed and returned; - BUG#9078: STORED PROCDURE: Decimal digits are not displayed when we use DECIMAL datatype; - BUG#9572: Stored procedures: variable type declarations ignored; - BUG#12903: upper function does not work inside a function; - BUG#13705: parameters to stored procedures are not verified; - BUG#13808: ENUM type stored procedure parameter accepts non-enumerated data; - BUG#13909: Varchar Stored Procedure Parameter always BINARY string (ignores CHARACTER SET); - BUG#14161: Stored procedure cannot retrieve bigint unsigned; - BUG#14188: BINARY variables have no 0x00 padding; - BUG#15148: Stored procedure variables accept non-scalar values; mysql-test/r/ctype_ujis.result: Explicitly specify correct charset. mysql-test/r/schema.result: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/r/show_check.result: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/r/skip_name_resolve.result: Ignore columns with unpredictable values. mysql-test/r/sp-big.result: Add cleanup statement. mysql-test/r/sp-dynamic.result: Add cleanup statements. mysql-test/r/sp.result: Update result file. mysql-test/r/sum_distinct-big.result: Update result file. mysql-test/r/type_newdecimal-big.result: Update result file. mysql-test/t/ctype_ujis.test: Explicitly specify correct charset. mysql-test/t/schema.test: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/t/show_check.test: Drop our test database to not affect this test if some test left it cause of failure. mysql-test/t/skip_name_resolve.test: Ignore columns with unpredictable values. mysql-test/t/sp-big.test: Add cleanup statement. mysql-test/t/sp-dynamic.test: Add cleanup statements. mysql-test/t/sp.test: Non-scalar values prohibited for assignment to SP-vars; polishing. mysql-test/t/type_newdecimal-big.test: Update type specification so that the variables can contain the large values used in the test. sql/field.cc: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/field.h: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/item.cc: - Introduce a new class: Item_sp_variable -- a base class of stored-routine-variables classes; - Introduce Item_case_expr -- an Item, which is used to access to the expression of CASE statement; sql/item.h: - Introduce a new class: Item_sp_variable -- a base class of stored-routine-variables classes; - Introduce Item_case_expr -- an Item, which is used to access to the expression of CASE statement; sql/item_func.cc: Pass the Field (instead of Item) for the return value of a function to the function execution routine. sql/item_func.h: Pass the Field (instead of Item) for the return value of a function to the function execution routine. sql/mysql_priv.h: Move create_virtual_tmp_table() out of sql_select.h. sql/sp.cc: Use create_result_field() instead of make_field(). sql/sp_head.cc: - Add a function to map enum_field_types to Item::Type; - Add sp_instr_push_case_expr instruction -- an instruction to push CASE expression into the active running context; - Add sp_instr_pop_case_expr instruction -- an instruction to pop CASE expression from the active running context; - Adapt the SP-execution code to using Fields instead of Items for SP-vars; - Use create_field structure for field description instead of a set of members. sql/sp_head.h: - Add a function to map enum_field_types to Item::Type; - Add sp_instr_push_case_expr instruction -- an instruction to push CASE expression into the active running context; - Add sp_instr_pop_case_expr instruction -- an instruction to pop CASE expression from the active running context; - Adapt the SP-execution code to using Fields instead of Items for SP-vars; - Use create_field structure for field description instead of a set of members. sql/sp_pcontext.cc: - Change rules to assign an index of SP-variable: use transparent index; - Add an operation to retrieve a list of defined SP-vars from the processing context recursively. sql/sp_pcontext.h: - Change rules to assign an index of SP-variable: use transparent index; - Add an operation to retrieve a list of defined SP-vars from the processing context recursively. sql/sp_rcontext.cc: - Change rules to assign an index of SP-variable: use transparent index; - Use a tmp virtual table to store SP-vars instead of Items; - Provide operations to work with CASE expresion. sql/sp_rcontext.h: - Change rules to assign an index of SP-variable: use transparent index; - Use a tmp virtual table to store SP-vars instead of Items; - Provide operations to work with CASE expresion. sql/sql_class.cc: - Reflect Item_splocal ctor changes; - Item_splocal::get_offset() has been renamed to get_var_idx(). sql/sql_class.h: Polishing. sql/sql_parse.cc: Extract create_field::init() to initialize an existing instance of create_field from new_create_field(). sql/sql_select.cc: Take care of BLOB columns in create_virtual_tmp_table(). sql/sql_select.h: Move create_virtual_tmp_table() out of sql_select.h. sql/sql_trigger.cc: Use boolean constants for boolean type instead of numerical ones. sql/sql_yacc.yy: Provide an instance of create_field for each SP-var. mysql-test/include/sp-vars.inc: The definitions of common-procedures, which are created under different circumstances. mysql-test/r/sp-vars.result: Result file for the SP-vars test. mysql-test/sp-vars.test: A new test for checking SP-vars functionality.
352 lines
8.9 KiB
Text
352 lines
8.9 KiB
Text
delimiter |;
|
|
|
|
--disable_warnings
|
|
drop procedure if exists p1|
|
|
drop procedure if exists p2|
|
|
--enable_warnings
|
|
|
|
######################################################################
|
|
# Test Dynamic SQL in stored procedures. #############################
|
|
######################################################################
|
|
#
|
|
# A. Basics
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt from "select 1";
|
|
execute stmt;
|
|
execute stmt;
|
|
execute stmt;
|
|
deallocate prepare stmt;
|
|
end|
|
|
call p1()|
|
|
call p1()|
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# B. Recursion. Recusion is disabled in SP, and recursive use of PS is not
|
|
# possible as well.
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
execute stmt;
|
|
end|
|
|
prepare stmt from "call p1()"|
|
|
# Allow SP resursion to be show that it has not influence here
|
|
set @SAVE_SP_RECURSION_LEVELS=@@max_sp_recursion_depth|
|
|
set @@max_sp_recursion_depth=100|
|
|
--error ER_PS_NO_RECURSION
|
|
execute stmt|
|
|
--error ER_PS_NO_RECURSION
|
|
execute stmt|
|
|
--error ER_PS_NO_RECURSION
|
|
execute stmt|
|
|
--error ER_PS_NO_RECURSION
|
|
call p1()|
|
|
--error ER_PS_NO_RECURSION
|
|
call p1()|
|
|
--error ER_PS_NO_RECURSION
|
|
call p1()|
|
|
set @@max_sp_recursion_depth=@SAVE_SP_RECURSION_LEVELS|
|
|
--error ER_SP_RECURSION_LIMIT
|
|
call p1()|
|
|
--error ER_SP_RECURSION_LIMIT
|
|
call p1()|
|
|
--error ER_SP_RECURSION_LIMIT
|
|
call p1()|
|
|
|
|
drop procedure p1|
|
|
#
|
|
# C. Create/drop a stored procedure in Dynamic SQL.
|
|
# One cannot create stored procedure from a stored procedure because of
|
|
# the way MySQL SP cache works: it's important that this limitation is not
|
|
# possible to circumvent by means of Dynamic SQL.
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt from "create procedure p2() begin select 1; end";
|
|
execute stmt;
|
|
deallocate prepare stmt;
|
|
end|
|
|
--error ER_UNSUPPORTED_PS
|
|
call p1()|
|
|
--error ER_UNSUPPORTED_PS
|
|
call p1()|
|
|
drop procedure p1|
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt from "drop procedure p2";
|
|
execute stmt;
|
|
deallocate prepare stmt;
|
|
end|
|
|
--error ER_UNSUPPORTED_PS
|
|
call p1()|
|
|
--error ER_UNSUPPORTED_PS
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# D. Create/Drop a table (a DDL that issues a commit) in Dynamic SQL.
|
|
# (should work ok).
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt_drop from "drop table if exists t1";
|
|
execute stmt_drop;
|
|
prepare stmt from "create table t1 (a int)";
|
|
execute stmt;
|
|
insert into t1 (a) values (1);
|
|
select * from t1;
|
|
deallocate prepare stmt;
|
|
deallocate prepare stmt_drop;
|
|
end|
|
|
call p1()|
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# A more real example (a case similar to submitted by 24/7).
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
set @tab_name=concat("tab_", replace(curdate(), '-', '_'));
|
|
set @drop_sql=concat("drop table if exists ", @tab_name);
|
|
set @create_sql=concat("create table ", @tab_name, " (a int)");
|
|
set @insert_sql=concat("insert into ", @tab_name, " values (1), (2), (3)");
|
|
set @select_sql=concat("select * from ", @tab_name);
|
|
select @tab_name;
|
|
select @drop_sql;
|
|
select @create_sql;
|
|
select @insert_sql;
|
|
select @select_sql;
|
|
prepare stmt_drop from @drop_sql;
|
|
execute stmt_drop;
|
|
prepare stmt from @create_sql;
|
|
execute stmt;
|
|
prepare stmt from @insert_sql;
|
|
execute stmt;
|
|
prepare stmt from @select_sql;
|
|
execute stmt;
|
|
execute stmt_drop;
|
|
deallocate prepare stmt;
|
|
deallocate prepare stmt_drop;
|
|
end|
|
|
--disable_result_log
|
|
call p1()|
|
|
call p1()|
|
|
--enable_result_log
|
|
drop procedure p1|
|
|
#
|
|
# E. Calling a stored procedure with Dynamic SQL
|
|
# from a stored function (currently disabled).
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt_drop from "drop table if exists t1";
|
|
execute stmt_drop;
|
|
prepare stmt from "create table t1 (a int)";
|
|
execute stmt;
|
|
deallocate prepare stmt;
|
|
deallocate prepare stmt_drop;
|
|
end|
|
|
--disable_warnings
|
|
drop function if exists f1|
|
|
--enable_warnings
|
|
create function f1(a int) returns int
|
|
begin
|
|
call p1();
|
|
return 1;
|
|
end|
|
|
|
|
# Every stored procedure that contains Dynamic SQL is marked as
|
|
# such. Stored procedures that contain Dynamic SQL are not
|
|
# allowed in a stored function or trigger, and here we get the
|
|
# corresponding error message.
|
|
|
|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
|
|
select f1(0)|
|
|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
|
|
select f1(f1(0))|
|
|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
|
|
select f1(f1(f1(0)))|
|
|
drop function f1|
|
|
drop procedure p1|
|
|
#
|
|
# F. Rollback and cleanup lists management in Dynamic SQL.
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
drop table if exists t1;
|
|
create table t1 (id integer not null primary key,
|
|
name varchar(20) not null);
|
|
insert into t1 (id, name) values (1, 'aaa'), (2, 'bbb'), (3, 'ccc');
|
|
prepare stmt from "select name from t1";
|
|
execute stmt;
|
|
select name from t1;
|
|
execute stmt;
|
|
prepare stmt from
|
|
"select name from t1 where name=(select name from t1 where id=2)";
|
|
execute stmt;
|
|
select name from t1 where name=(select name from t1 where id=2);
|
|
execute stmt;
|
|
end|
|
|
call p1()|
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# H. Executing a statement prepared externally in SP.
|
|
#
|
|
prepare stmt from "select * from t1"|
|
|
create procedure p1()
|
|
begin
|
|
execute stmt;
|
|
deallocate prepare stmt;
|
|
end|
|
|
call p1()|
|
|
--error ER_UNKNOWN_STMT_HANDLER
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# I. Use of an SP variable in Dynamic SQL is not possible and
|
|
# this limitation is necessary for correct binary logging: prepared
|
|
# statements do not substitute SP variables with their values for binlog, so
|
|
# SP variables must be not accessible in Dynamic SQL.
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
declare a char(10);
|
|
set a="sp-variable";
|
|
set @a="mysql-variable";
|
|
prepare stmt from "select 'dynamic sql:', @a, a";
|
|
execute stmt;
|
|
end|
|
|
--error ER_BAD_FIELD_ERROR
|
|
call p1()|
|
|
--error ER_BAD_FIELD_ERROR
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# J. Use of placeholders in Dynamic SQL.
|
|
#
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt from 'select ? as a';
|
|
execute stmt using @a;
|
|
end|
|
|
set @a=1|
|
|
call p1()|
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# K. Use of continue handlers with Dynamic SQL.
|
|
#
|
|
drop table if exists t1|
|
|
create table t1 (id integer primary key auto_increment,
|
|
stmt_text char(35), status varchar(20))|
|
|
insert into t1 (stmt_text) values
|
|
("select 1"), ("flush tables"), ("handler t1 open as ha"),
|
|
("analyze table t1"), ("check table t1"), ("checksum table t1"),
|
|
("check table t1"), ("optimize table t1"), ("repair table t1"),
|
|
("describe extended select * from t1"),
|
|
("help help"), ("show databases"), ("show tables"),
|
|
("show table status"), ("show open tables"), ("show storage engines"),
|
|
("insert into t1 (id) values (1)"), ("update t1 set status=''"),
|
|
("delete from t1"), ("truncate t1"), ("call p1()"), ("foo bar")|
|
|
create procedure p1()
|
|
begin
|
|
declare v_stmt_text varchar(255);
|
|
declare v_id integer;
|
|
declare done int default 0;
|
|
declare c cursor for select id, stmt_text from t1;
|
|
declare continue handler for 1295 -- ER_UNSUPPORTED_PS
|
|
set @status='not supported';
|
|
declare continue handler for 1064 -- ER_SYNTAX_ERROR
|
|
set @status='syntax error';
|
|
declare continue handler for sqlstate '02000' set done = 1;
|
|
|
|
prepare update_stmt from "update t1 set status=? where id=?";
|
|
open c;
|
|
repeat
|
|
if not done then
|
|
fetch c into v_id, v_stmt_text;
|
|
set @id=v_id, @stmt_text=v_stmt_text;
|
|
set @status="supported";
|
|
prepare stmt from @stmt_text;
|
|
execute update_stmt using @status, @id;
|
|
end if;
|
|
until done end repeat;
|
|
deallocate prepare update_stmt;
|
|
end|
|
|
call p1()|
|
|
select * from t1|
|
|
drop procedure p1|
|
|
drop table t1|
|
|
#
|
|
# Bug#7115 "Prepared Statements: packet error if execution within stored
|
|
# procedure".
|
|
#
|
|
prepare stmt from 'select 1'|
|
|
create procedure p1() execute stmt|
|
|
call p1()|
|
|
call p1()|
|
|
drop procedure p1|
|
|
#
|
|
# Bug#10975 "Prepared statements: crash if function deallocates"
|
|
# Check that a prepared statement that is currently in use
|
|
# can't be deallocated.
|
|
#
|
|
# a) Prepared statements and stored procedure cache:
|
|
#
|
|
# TODO: add when the corresponding bug (Bug #12093 "SP not found on second
|
|
# PS execution if another thread drops other SP in between") is fixed.
|
|
#
|
|
# b) attempt to deallocate a prepared statement that is being executed
|
|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
|
|
create function f1() returns int
|
|
begin
|
|
deallocate prepare stmt;
|
|
return 1;
|
|
end|
|
|
|
|
# b)-2 a crash (#1) spotted by Sergey Petrunia during code review
|
|
create procedure p1()
|
|
begin
|
|
prepare stmt from 'select 1 A';
|
|
execute stmt;
|
|
end|
|
|
prepare stmt from 'call p1()'|
|
|
--error ER_PS_NO_RECURSION
|
|
execute stmt|
|
|
--error ER_PS_NO_RECURSION
|
|
execute stmt|
|
|
drop procedure p1|
|
|
|
|
#
|
|
# Bug#10605 "Stored procedure with multiple SQL prepared statements
|
|
# disconnects client"
|
|
#
|
|
--disable_warnings
|
|
drop table if exists t1, t2|
|
|
--enable_warnings
|
|
create procedure p1 (a int) language sql deterministic
|
|
begin
|
|
declare rsql varchar(100);
|
|
drop table if exists t1, t2;
|
|
set @rsql= "create table t1 (a int)";
|
|
select @rsql;
|
|
prepare pst from @rsql;
|
|
execute pst;
|
|
set @rsql= null;
|
|
set @rsql= "create table t2 (a int)";
|
|
select @rsql;
|
|
prepare pst from @rsql;
|
|
execute pst;
|
|
drop table if exists t1, t2;
|
|
end|
|
|
set @a:=0|
|
|
call p1(@a)|
|
|
select @a|
|
|
call p1(@a)|
|
|
select @a|
|
|
drop procedure if exists p1|
|
|
|
|
# End of the test
|
|
delimiter ;|
|