diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2017-11-06 14:35:58 +0100 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2017-11-13 14:31:49 +0100 |
commit | efc18ad7d290a2b767f4f9e3d35905f3d236ecd0 (patch) | |
tree | 97f8b369bddada5618f449afd7c78951a2b75c5b | |
parent | 1fdf11669c1295bb49f50d1aaefec2d93bb24191 (diff) | |
download | mariadb-git-efc18ad7d290a2b767f4f9e3d35905f3d236ecd0.tar.gz |
MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loopsbb-10.1-MDEV-13936
Repeat reworked solution of procedures for all posible Sp (functions &
triggers).
-rw-r--r-- | mysql-test/r/sp.result | 12 | ||||
-rw-r--r-- | mysql-test/r/trigger.result | 17 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 17 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 24 | ||||
-rw-r--r-- | sql/sp_head.cc | 42 |
5 files changed, 93 insertions, 19 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index c6867d46489..9b0ace5c002 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8107,4 +8107,16 @@ CALL p(); drop procedure p; drop view v; 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 diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 86219875bed..8455450e294 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2290,3 +2290,20 @@ INSERT INTO t1 VALUES ('a'); ERROR 22001: Data too long for column 'c' at row 1 DROP TRIGGER t1_bi; 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. diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 99020eb951f..7453cec8f21 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9588,4 +9588,21 @@ drop procedure p; drop view v; 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 diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index a02dce34837..ff6f38b719d 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2634,3 +2634,27 @@ INSERT INTO t1 VALUES ('a'); DROP TRIGGER t1_bi; 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. diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 257a1d36a2a..31e4678a5e4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -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)) 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_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) m_recursion_level + 1)); 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 || thd->is_error()) + set_select_number(thd->select_number); + DBUG_RETURN(err_status); } @@ -2099,26 +2122,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) 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); - 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) |