Commit 0f43279c authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops

Repeat reworked solution of procedures for all posible Sp (functions &
triggers).
parent 05103c84
...@@ -8107,4 +8107,16 @@ CALL p(); ...@@ -8107,4 +8107,16 @@ CALL p();
drop procedure p; drop procedure p;
drop view v; drop view v;
drop table t, tmp_t; drop table t, tmp_t;
#
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
#
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
REPLACE INTO v1 VALUES (f1());
ERROR HY000: The target table v1 of the INSERT is not insertable-into
SET @aux = f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
#End of 10.1 tests #End of 10.1 tests
...@@ -2290,3 +2290,20 @@ INSERT INTO t1 VALUES ('a'); ...@@ -2290,3 +2290,20 @@ INSERT INTO t1 VALUES ('a');
ERROR 22001: Data too long for column 'c' at row 1 ERROR 22001: Data too long for column 'c' at row 1
DROP TRIGGER t1_bi; DROP TRIGGER t1_bi;
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
#
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
create trigger trg after insert on t2 for each row
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
drop table t1;
insert into t2 value (2);
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
End of 10.1 tests.
...@@ -9588,4 +9588,21 @@ drop procedure p; ...@@ -9588,4 +9588,21 @@ drop procedure p;
drop view v; drop view v;
drop table t, tmp_t; drop table t, tmp_t;
--echo #
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
--echo #
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
--error ER_NON_INSERTABLE_TABLE
REPLACE INTO v1 VALUES (f1());
SET @aux = f1();
# Cleanup
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
--echo #End of 10.1 tests --echo #End of 10.1 tests
...@@ -2634,3 +2634,27 @@ INSERT INTO t1 VALUES ('a'); ...@@ -2634,3 +2634,27 @@ INSERT INTO t1 VALUES ('a');
DROP TRIGGER t1_bi; DROP TRIGGER t1_bi;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
--echo #
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
create trigger trg after insert on t2 for each row
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
drop table t1;
--error ER_NO_SUCH_TABLE
insert into t2 value (2);
CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
--echo End of 10.1 tests.
...@@ -1136,6 +1136,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success) ...@@ -1136,6 +1136,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet)) if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/*
Normally the counter is not reset between parsing and first execution,
but it is possible in case of error to have parsing on one CALL and
first execution (where VIEW will be parsed and added). So we store the
counter after parsing and restore it before execution just to avoid
repeating SELECT numbers.
Other problem is that it can be more SELECTs parsed in case of fixing
error causes previous interruption of the SP. So it is save not just
assign old value but add it.
*/
thd->select_number+= m_select_number;
/* init per-instruction memroot */ /* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
...@@ -1469,6 +1482,16 @@ sp_head::execute(THD *thd, bool merge_da_on_success) ...@@ -1469,6 +1482,16 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
m_recursion_level + 1)); m_recursion_level + 1));
m_first_instance->m_first_free_instance= this; m_first_instance->m_first_free_instance= this;
/*
This execution of the SP was aborted with an error (e.g. "Table not
found"). However it might still have consumed some numbers from the
thd->select_number counter. The next sp->exec() call must not use the
consumed numbers, so we remember the first free number (We know that
nobody will use it as this execution has stopped with an error).
*/
if (err_status)
set_select_number(thd->select_number);
DBUG_RETURN(err_status); DBUG_RETURN(err_status);
} }
...@@ -2099,26 +2122,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) ...@@ -2099,26 +2122,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!err_status) if (!err_status)
{ {
/*
Normally the counter is not reset between parsing and first execution,
but it is possible in case of error to have parsing on one CALL and
first execution (where VIEW will be parsed and added). So we store the
counter after parsing and restore it before execution just to avoid
repeating SELECT numbers.
*/
thd->select_number= m_select_number;
err_status= execute(thd, TRUE); err_status= execute(thd, TRUE);
DBUG_PRINT("info", ("execute returned %d", (int) err_status));
/*
This execution of the SP was aborted with an error (e.g. "Table not
found"). However it might still have consumed some numbers from the
thd->select_number counter. The next sp->exec() call must not use the
consumed numbers, so we remember the first free number (We know that
nobody will use it as this execution has stopped with an error).
*/
if (err_status)
set_select_number(thd->select_number);
} }
if (save_log_general) if (save_log_general)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment