mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +03:00 
			
		
		
		
	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.
		
	
		
			
				
	
	
		
			353 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 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 ;|
 |