mariadb/mysql-test/main/sp-bugs.test

374 lines
7.8 KiB
Text
Raw Normal View History

# Test file for stored procedure bugfixes
--echo #
--echo # Bug #47412: Valgrind warnings / user can read uninitialized memory
--echo # using SP variables
--echo #
CREATE SCHEMA testdb;
USE testdb;
DELIMITER |;
CREATE FUNCTION f2 () RETURNS INTEGER
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1;
RETURN f_not_exists () ;
END|
CREATE PROCEDURE p3 ( arg1 VARCHAR(32) )
BEGIN
CALL p_not_exists ( );
END|
DELIMITER ;|
--echo # should not return valgrind warnings
--error ER_SP_DOES_NOT_EXIST
CALL p3 ( f2 () );
DROP SCHEMA testdb;
CREATE SCHEMA testdb;
USE testdb;
DELIMITER |;
CREATE FUNCTION f2 () RETURNS INTEGER
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1;
RETURN f_not_exists () ;
END|
CREATE PROCEDURE p3 ( arg2 INTEGER )
BEGIN
CALL p_not_exists ( );
END|
DELIMITER ;|
--echo # should not return valgrind warnings
--error ER_SP_DOES_NOT_EXIST
CALL p3 ( f2 () );
DROP SCHEMA testdb;
CREATE SCHEMA testdb;
USE testdb;
DELIMITER |;
CREATE FUNCTION f2 () RETURNS INTEGER
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1;
RETURN f_not_exists () ;
END|
DELIMITER ;|
--echo # should not return valgrind warnings
SELECT f2 ();
DROP SCHEMA testdb;
USE test;
--echo #
--echo # Bug#50423: Crash on second call of a procedure dropping a trigger
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TRIGGER IF EXISTS tr1;
DROP PROCEDURE IF EXISTS p1;
--enable_warnings
CREATE TABLE t1 (f1 INTEGER);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @aux = 1;
CREATE PROCEDURE p1 () DROP TRIGGER tr1;
CALL p1 ();
--error ER_TRG_DOES_NOT_EXIST
CALL p1 ();
DROP TABLE t1;
DROP PROCEDURE p1;
--echo #
--echo # Bug#50423: Crash on second call of a procedure dropping a trigger
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TRIGGER IF EXISTS tr1;
DROP PROCEDURE IF EXISTS p1;
--enable_warnings
CREATE TABLE t1 (f1 INTEGER);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @aux = 1;
CREATE PROCEDURE p1 () DROP TRIGGER tr1;
CALL p1 ();
--error ER_TRG_DOES_NOT_EXIST
CALL p1 ();
DROP TABLE t1;
DROP PROCEDURE p1;
--echo #
--echo # Bug#54375: Error in stored procedure leaves connection
--echo # in different default schema
--echo #
--disable_warnings
SET @@SQL_MODE = 'STRICT_ALL_TABLES';
DROP DATABASE IF EXISTS db1;
CREATE DATABASE db1;
USE db1;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 int NOT NULL PRIMARY KEY);
INSERT INTO t1 VALUES (1);
DELIMITER $$;
CREATE FUNCTION f1 (
some_value int
)
RETURNS smallint
DETERMINISTIC
BEGIN
INSERT INTO t1 SET c1 = some_value;
RETURN(LAST_INSERT_ID());
END$$
DELIMITER ;$$
DROP DATABASE IF EXISTS db2;
CREATE DATABASE db2;
--enable_warnings
USE db2;
SELECT DATABASE();
--error ER_DUP_ENTRY
SELECT db1.f1(1);
SELECT DATABASE();
USE test;
DROP FUNCTION db1.f1;
DROP TABLE db1.t1;
DROP DATABASE db1;
DROP DATABASE db2;
USE test;
Bug#13105873 :Valgrind Warning: CRASH IN FOREIGN KEY HANDLING ON SUBSEQUENT CREATE TABLE IF NOT EXISTS PROBLEM: -------- Consider a SP routine which does CREATE TABLE with REFERENCES clause. The first call to this routine invokes parser and the parsed items are cached, so as to avoid parsing for the second execution of the routine. It is obsevered that valgrind reports a warning upon read of thd->lex->alter_info->key_list->Foreign_key object, which seem to be pointing to a invalid memory address during second time execution of the routine. Accessing this object theoretically could cause a crash. ANALYSIS: --------- The problem stems from the fact that for some reason elements of ref_columns list in thd->lex->alter_info-> key_list->Foreign_key object are changed to point to objects allocated on runtime memory root. During the first execution of routine we create a copy of thd->lex->alter_info object. As part of this process we create a clones of objects in Alter_info::key_list and of Foreign_key object in particular. Then Foreign_key object is cloned for some reason we perform shallow copies of both Foreign_key::ref_columns and Foreign_key::columns list. So new instance of Foreign_key object starts to SHARE contents of ref_columns and columns list with the original instance. After that as part of cloning process we call list_copy_and_replace_each_value() for elements of ref_columns list. As result ref_columns lists in both original and cloned Foreign_key object start to contain pointers to Key_part_spec objects allocated on runtime memory root because of shallow copy. So when we start copying of thd->lex->alter_info object during the second execution of stored routine we indeed encounter pointer to the Key_part_spec object allocated on runtime mem-root which was cleared during at the end of previous execution. This is done in sp_head::execute(), by a call to free_root(&execute_mem_root,MYF(0)); As result we get valgrind warnings about accessing unreferenced memory. FIX: ---- The safest solution to this problem is to fix Foreign_key(Foreign_key, MEM_ROOT) constructor to do a deep copy of columns lists, similar to Key(Key, MEM_ROOT) constructor.
2012-01-30 07:27:33 +01:00
--echo #
--echo # Bug#13105873:valgrind warning:possible crash in foreign
--echo # key handling on subsequent create table if not exists
--echo #
--disable_warnings
DROP DATABASE IF EXISTS testdb;
--enable_warnings
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE t1 (id1 INT PRIMARY KEY);
DELIMITER $;
CREATE PROCEDURE `p1`()
BEGIN
CREATE TABLE IF NOT EXISTS t2(id INT PRIMARY KEY,
CONSTRAINT FK FOREIGN KEY (id) REFERENCES t1( id1 ));
END$
DELIMITER ;$
CALL p1();
--echo # below stmt should not return valgrind warnings
CALL p1();
DROP DATABASE testdb;
USE test;
Bug#13105873 :Valgrind Warning: CRASH IN FOREIGN KEY HANDLING ON SUBSEQUENT CREATE TABLE IF NOT EXISTS PROBLEM: -------- Consider a SP routine which does CREATE TABLE with REFERENCES clause. The first call to this routine invokes parser and the parsed items are cached, so as to avoid parsing for the second execution of the routine. It is obsevered that valgrind reports a warning upon read of thd->lex->alter_info->key_list->Foreign_key object, which seem to be pointing to a invalid memory address during second time execution of the routine. Accessing this object theoretically could cause a crash. ANALYSIS: --------- The problem stems from the fact that for some reason elements of ref_columns list in thd->lex->alter_info-> key_list->Foreign_key object are changed to point to objects allocated on runtime memory root. During the first execution of routine we create a copy of thd->lex->alter_info object. As part of this process we create a clones of objects in Alter_info::key_list and of Foreign_key object in particular. Then Foreign_key object is cloned for some reason we perform shallow copies of both Foreign_key::ref_columns and Foreign_key::columns list. So new instance of Foreign_key object starts to SHARE contents of ref_columns and columns list with the original instance. After that as part of cloning process we call list_copy_and_replace_each_value() for elements of ref_columns list. As result ref_columns lists in both original and cloned Foreign_key object start to contain pointers to Key_part_spec objects allocated on runtime memory root because of shallow copy. So when we start copying of thd->lex->alter_info object during the second execution of stored routine we indeed encounter pointer to the Key_part_spec object allocated on runtime mem-root which was cleared during at the end of previous execution. This is done in sp_head::execute(), by a call to free_root(&execute_mem_root,MYF(0)); As result we get valgrind warnings about accessing unreferenced memory. FIX: ---- The safest solution to this problem is to fix Foreign_key(Foreign_key, MEM_ROOT) constructor to do a deep copy of columns lists, similar to Key(Key, MEM_ROOT) constructor.
2012-01-30 07:27:33 +01:00
--echo End of 5.1 tests
--echo #
--echo # BUG#13489996 valgrind:conditional jump or move depends on
--echo # uninitialised values-field_blob
--echo #
CREATE FUNCTION sf() RETURNS BLOB RETURN "";
SELECT sf();
DROP FUNCTION sf;
--echo #
--echo # Bug#11763507 - 56224: FUNCTION NAME IS CASE-SENSITIVE
--echo #
SET @@SQL_MODE = '';
DELIMITER $;
CREATE FUNCTION testf_bug11763507() RETURNS INT
BEGIN
RETURN 0;
END
$
CREATE PROCEDURE testp_bug11763507()
BEGIN
SELECT "PROCEDURE testp_bug11763507";
END
$
DELIMITER ;$
# STORED FUNCTIONS
SELECT testf_bug11763507();
SELECT TESTF_bug11763507();
--replace_column 5 # 6 #
SHOW FUNCTION STATUS LIKE 'testf_bug11763507';
--replace_column 5 # 6 #
SHOW FUNCTION STATUS WHERE NAME='testf_bug11763507';
--replace_column 5 # 6 #
SHOW FUNCTION STATUS LIKE 'TESTF_bug11763507';
--replace_column 5 # 6 #
SHOW FUNCTION STATUS WHERE NAME='TESTF_bug11763507';
SHOW CREATE FUNCTION testf_bug11763507;
SHOW CREATE FUNCTION TESTF_bug11763507;
# STORED PROCEDURE
CALL testp_bug11763507();
CALL TESTP_bug11763507();
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'testp_bug11763507';
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS WHERE NAME='testp_bug11763507';
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'TESTP_bug11763507';
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS WHERE NAME='TESTP_bug11763507';
SHOW CREATE PROCEDURE testp_bug11763507;
SHOW CREATE PROCEDURE TESTP_bug11763507;
# INFORMATION SCHEMA
SELECT specific_name FROM INFORMATION_SCHEMA.ROUTINES WHERE specific_name LIKE 'testf_bug11763507';
SELECT specific_name FROM INFORMATION_SCHEMA.ROUTINES WHERE specific_name LIKE 'TESTF_bug11763507';
SELECT specific_name FROM INFORMATION_SCHEMA.ROUTINES WHERE specific_name='testf_bug11763507';
SELECT specific_name FROM INFORMATION_SCHEMA.ROUTINES WHERE specific_name='TESTF_bug11763507';
DROP PROCEDURE testp_bug11763507;
DROP FUNCTION testf_bug11763507;
--echo #END OF BUG#11763507 test.
Fix for MDEV-5531: double call procedure in one session - hard shutdown the server Main fix was to not cache derivied tables as they may be temporary tables that are deleted before the next query. This was a bit tricky as Item_field::fix_fields depended on cached_tables to be set to resolve some columns. mysql-test/r/sp-bugs.result: Added test case mysql-test/t/sp-bugs.test: Added test case sql/item.cc: Fixed fix_outer_field to handle case where found field did not have in cached_table Idea is that if cached_table is not avaliable, use from_field->table->pos_in_table_list instead sql/records.cc: Also accept INTERNAL_TMP_TABLE for memmap sql/sql_base.cc: More DBUG_PRINT Fixed that setup_natural_join_row_types() is not run twice. Original code modified context->first_name_resolution_table also for second executions. This was wrong as this could give wrong results if some joins had been optimized away between calls. sql/sql_derived.cc: Mark derived tables as internal temporary tables (INTERNAL_TMP_TABLE), not as NON_TRANSACTIONAL_TMP_TABLE. This is more correct as the tables are not visible by the end user. sql/sql_insert.cc: Reset pos_in_table_list before calling fix_fields. One of the consequences of the change of not caching all generated tables in Item_ident is that pos_in_table_list needs to be correct in calls to fix_fields. sql/sql_lex.cc: More DBUG_PRINT sql/sql_parse.cc: Don't cache derivied tables as they may be temporary tables that are deleted before the next query sql/sql_select.cc: Reset table_vector. This was required as some code checked the vector to see if temporary tables had already been created. sql/table.cc: Mark tables with field translations as cacheable (as these will not disapper between stmt executions.
2014-01-24 13:50:18 +01:00
--echo #
--echo # MDEV-5531 double call procedure in one session
--echo #
CREATE TABLE `t1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`create_ts` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
DELIMITER $$;
CREATE PROCEDURE test_5531 (IN step TINYINT(1))
BEGIN
DECLARE counts INT DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT ct.id
FROM (SELECT NULL) AS z
JOIN (
SELECT id
FROM `t1`
LIMIT 10
) AS ct
JOIN (SELECT NULL) AS x ON(
EXISTS(
SELECT 1
FROM `t1`
WHERE id=ct.id
LIMIT 1
)
);
IF step=1 THEN
TRUNCATE t1;
REPEAT
INSERT INTO `t1`
(create_ts) VALUES
(UNIX_TIMESTAMP());
SET counts=counts+1;
UNTIL counts>150 END REPEAT;
SET max_sp_recursion_depth=1;
CALL test_5531(2);
SET max_sp_recursion_depth=2;
CALL test_5531(2);
ELSEIF step=2 THEN
OPEN cur1; CLOSE cur1;
END IF;
END $$
DELIMITER ;$$
CALL test_5531(1);
DROP PROCEDURE test_5531;
DROP TABLE t1;
#
# MDEV-6601 Assertion `!thd->in_active_multi_stmt_transa ction() || thd->in_multi_stmt_transaction_mode()' failed on executing a stored procedure with commit
#
delimiter |;
create procedure sp() begin
commit;
end|
delimiter ;|
start transaction;
call sp();
drop procedure sp;
--echo #
--echo # MDEV-11146 SP variables of the SET data type erroneously allow values with comma
--echo #
DELIMITER $$;
--error ER_ILLEGAL_VALUE_FOR_TYPE
CREATE PROCEDURE p1()
BEGIN
DECLARE a SET('a','b','c','a,b');
SET a='a,b';
SELECT a, a+0;
END;
$$
DELIMITER ;$$
MDEV-16117 SP with a single FOR statement creates but further fails to load The code in the "sp_tail" rule in sql_yacc.yy always used YYLIP->get_cpp_tok_start() as the start of the body, and did not check for possible lookahead which happens for keywords "FOR", "VALUES" and "WITH" for LALR(2) resolution in Lex_input_stream::lex_token(). In case of the lookahead token presence, get_tok_start_prev() should have been used instead of get_cpp_tok_start() as the beginning of the SP body. Change summary: This patch hides the implementation of the lookahead token completely inside Lex_input_stream. The users of Lex_input_stream now just get token-by-token transparently and should not care about lookahead any more. Now external users of Lex_input_stream are not aware of the lookahead token at all. Change details: - Moving Lex_input_stream::has_lookahead() into the "private" section. - Removing Lex_input_stream::get_tok_start_prev() and Lex_input_stream::get_cpp_start_prev(). - Fixing the external code to call get_tok_start() and get_cpp_tok_start() in all places where get_tok_start_prev() and get_cpp_start_prev() where used. - Adding a test for has_lookahead() right inside get_tok_start() and get_cpp_tok_start(). If there is a lookahead token, these methods now return the position of the previous token automatically: const char *get_tok_start() { return has_lookahead() ? m_tok_start_prev : m_tok_start; } const char *get_cpp_tok_start() { return has_lookahead() ? m_cpp_tok_start_prev : m_cpp_tok_start; } - Fixing the internal code inside Lex_input_stream methods to use m_tok_start and m_cpp_tok_start directly, instead of calling get_tok_start() and get_cpp_tok_start(), to make sure to access to the *current* token position (independently of a lookahead token presence).
2018-05-10 13:55:33 +02:00
--echo #
--echo # Start of 10.3 tests
--echo #
--echo #
--echo # MDEV-16117 SP with a single FOR statement creates but further fails to load
--echo #
DELIMITER $$;
CREATE PROCEDURE p1()
FOR i IN 1..10 DO
set @x = 5;
END FOR;
$$
DELIMITER ;$$
CALL p1;
SELECT body FROM mysql.proc WHERE db='test' AND specific_name='p1';
DROP PROCEDURE p1;
DELIMITER $$;
CREATE PROCEDURE p1() WITH t1 AS (SELECT 1) SELECT 1;
$$
DELIMITER ;$$
CALL p1;
SELECT body FROM mysql.proc WHERE db='test' AND specific_name='p1';
DROP PROCEDURE p1;
DELIMITER $$;
CREATE PROCEDURE p1() VALUES (1);
$$
DELIMITER ;$$
CALL p1;
SELECT body FROM mysql.proc WHERE db='test' AND specific_name='p1';
DROP PROCEDURE p1;
DELIMITER $$;
CREATE FUNCTION f1() RETURNS INT
FOR i IN 1..10 DO
RETURN 1;
END FOR;
$$
DELIMITER ;$$
SELECT f1();
SELECT body FROM mysql.proc WHERE db='test' AND specific_name='f1';
DROP FUNCTION f1;