mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
eb057dce20
multiple times with different arguments. If the ON expression of an outer join is an OR formula with one of the disjunct being a constant formula then the expression cannot be null-rejected if the constant formula is true. Otherwise it can be null-rejected and if so the outer join can be converted into inner join. This optimization was added in the patch for mdev-4817. Yet the code had a defect: if the query was used in a stored procedure with parameters and the constant item contained some of them then the value of this constant item depended on the values of the parameters. With some parameters it may be true, for others not. The validity of conversion to inner join is checked only once and it happens only for the first call of procedure. So if the parameters in the first call allowed the conversion it was done and next calls used the transformed query though there could be calls whose parameters made the conversion invalid. Fixed by cheking whether the constant disjunct in the ON expression originally contained an SP parameter. If so the expression is not considered as null-rejected. For this check a new item's attribute was intruduced: Item::with_param. It is calculated for each item by fix fields() functions. Also moved the call of optimize_constant_subqueries() in JOIN::optimize after the call of simplify_joins(). The reason for this is that after the optimization introduced by the patch for mdev-4817 simplify_joins() can use the results of execution of non-expensive constant subqueries and this is not valid.
174 lines
4.4 KiB
Text
174 lines
4.4 KiB
Text
drop table if exists t1,t2;
|
|
drop procedure if exists p1;
|
|
#
|
|
#MDEV-6985: MariaDB crashes on stored procedure call
|
|
#
|
|
CREATE TABLE `t1` (
|
|
`ID` int(11) NOT NULL,
|
|
PRIMARY KEY (`ID`)
|
|
) ENGINE=InnoDB;
|
|
CREATE TABLE `t2` (
|
|
`ID` int(11) NOT NULL,
|
|
`DATE` datetime DEFAULT NULL,
|
|
PRIMARY KEY (`ID`)
|
|
) ENGINE=InnoDB;
|
|
CREATE PROCEDURE `p1`()
|
|
BEGIN
|
|
DECLARE _mySelect CURSOR FOR
|
|
SELECT DISTINCT t1.ID
|
|
FROM t1
|
|
LEFT JOIN t2 AS t2 ON
|
|
t2.ID = t1.ID
|
|
AND t2.DATE = (
|
|
SELECT MAX(T3.DATE) FROM t2 AS T3 WHERE T3.ID = t2.ID AND T3.DATE<=NOW()
|
|
)
|
|
WHERE t1.ID = 1;
|
|
OPEN _mySelect;
|
|
CLOSE _mySelect;
|
|
END ;;
|
|
CALL p1();
|
|
CALL p1();
|
|
drop procedure p1;
|
|
drop table t1,t2;
|
|
|
|
#
|
|
# BUG 16041903: CONTINUE HANDLER NOT INVOKED
|
|
# IN A STORED FUNCTION AFTER A LOCK WAIT TIMEOUT
|
|
#
|
|
|
|
# Save and set lock wait timeout
|
|
SET @lock_wait_timeout_saved= @@lock_wait_timeout;
|
|
SET @innodb_lock_wait_timeout_saved= @@innodb_lock_wait_timeout;
|
|
SET @@lock_wait_timeout= 1;
|
|
SET @@innodb_lock_wait_timeout= 1;
|
|
|
|
# Create a function with exit handler:
|
|
CREATE FUNCTION f1() RETURNS VARCHAR(20)
|
|
BEGIN
|
|
DECLARE EXIT HANDLER FOR SQLSTATE '42S02' RETURN 'No such table';
|
|
INSERT INTO no_such_table VALUES (1);
|
|
END//
|
|
|
|
# Create a function calling f1():
|
|
CREATE FUNCTION f2() RETURNS VARCHAR(20)
|
|
BEGIN
|
|
RETURN f1();
|
|
END//
|
|
|
|
# Create a function provoking deadlock:
|
|
CREATE FUNCTION f3() RETURNS VARCHAR(20)
|
|
BEGIN
|
|
UPDATE t1 SET i= 1 WHERE i= 1;
|
|
RETURN 'Will never get here';
|
|
END//
|
|
|
|
# Create a function calling f3, to create
|
|
# a deadlock indirectly:
|
|
CREATE FUNCTION f4() RETURNS VARCHAR(20)
|
|
BEGIN
|
|
RETURN f3();
|
|
END//
|
|
|
|
# Open another connection, create and initialize a table
|
|
# to be used for provoking deadlock, put a lock on the table:
|
|
CREATE TABLE t1 (i INT) ENGINE=InnoDB;
|
|
INSERT INTO t1 VALUES (1);
|
|
SET AUTOCOMMIT= 0;
|
|
UPDATE t1 SET i=1 WHERE i=1;
|
|
|
|
# On the default connection, do an update to provoke a
|
|
# deadlock, then call the function with handler. This case
|
|
# fails without the patch (with error ER_NO_SUCH_TABLE):
|
|
SET AUTOCOMMIT= 0;
|
|
UPDATE t1 SET i=1 WHERE i=1;
|
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
|
SELECT f1() AS 'f1():';
|
|
f1():
|
|
No such table
|
|
Warnings:
|
|
Error 1146 Table 'test.no_such_table' doesn't exist
|
|
|
|
# Provoke another deadlock, then call the function with
|
|
# handler indirectly. This case fails without the patch
|
|
# (with error ER_NO_SUCH_TABLE):
|
|
UPDATE t1 SET i= 1 WHERE i= 1;
|
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
|
SELECT f2() AS 'f2():';
|
|
f2():
|
|
No such table
|
|
Warnings:
|
|
Error 1146 Table 'test.no_such_table' doesn't exist
|
|
|
|
# Provoke yet another deadlock, but now from within a function,
|
|
# then call the function with handler. This succeeds even
|
|
# without the patch because is_fatal_sub_stmt_error is reset
|
|
# in restore_sub_stmt after the failing function has been
|
|
# executed. The test case is included anyway for better coverage:
|
|
SELECT f3() AS 'f3():';
|
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
|
SELECT f1() AS 'f1():';
|
|
f1():
|
|
No such table
|
|
Warnings:
|
|
Error 1146 Table 'test.no_such_table' doesn't exist
|
|
# Provoke yet another deadlock, but now from within a function,
|
|
# calling another function, then call the function with handler.
|
|
# This succeeds even without the patch because
|
|
# is_fatal_sub_stmt_error is reset in restore_sub_stmt after
|
|
# the failing function has been executed. The test case is
|
|
# included anyway for better coverage:
|
|
SELECT f4() AS 'f4():';
|
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
|
SELECT f1() AS 'f1():';
|
|
f1():
|
|
No such table
|
|
Warnings:
|
|
Error 1146 Table 'test.no_such_table' doesn't exist
|
|
|
|
# Disconnect, drop functions and table:
|
|
DROP FUNCTION f4;
|
|
DROP FUNCTION f3;
|
|
DROP FUNCTION f2;
|
|
DROP FUNCTION f1;
|
|
DROP TABLE t1;
|
|
|
|
# Reset lock wait timeouts
|
|
SET @@lock_wait_timeout= @lock_wait_timeout_saved;
|
|
SET @@innodb_lock_wait_timeout= @innodb_lock_wait_timeout_saved;
|
|
#
|
|
# BUG 16041903: End of test case
|
|
#
|
|
#
|
|
# MDEV-15035: SP using query with outer join and a parameter
|
|
# in ON expression
|
|
#
|
|
CREATE TABLE t1 (
|
|
id int NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
INSERT INTO t1 VALUES (1), (2);
|
|
CREATE TABLE t2 (
|
|
id int NOT NULL,
|
|
id_foo int NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
INSERT INTO t2 VALUES (1, 1);
|
|
DROP PROCEDURE IF EXISTS test_proc;
|
|
CREATE PROCEDURE test_proc(IN param int)
|
|
LANGUAGE SQL
|
|
READS SQL DATA
|
|
BEGIN
|
|
SELECT DISTINCT f.id
|
|
FROM t1 f
|
|
LEFT OUTER JOIN t2 b ON b.id_foo = f.id
|
|
WHERE (param <> 0 OR b.id IS NOT NULL);
|
|
END|
|
|
CALL test_proc(0);
|
|
id
|
|
1
|
|
CALL test_proc(1);
|
|
id
|
|
1
|
|
2
|
|
DROP PROCEDURE IF EXISTS test_proc;
|
|
DROP TABLE t1, t2;
|