Skip to content

Commit 0f43279

Browse files
committed
MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
Repeat reworked solution of procedures for all posible Sp (functions & triggers).
1 parent 05103c8 commit 0f43279

File tree

5 files changed

+93
-19
lines changed

5 files changed

+93
-19
lines changed

mysql-test/r/sp.result

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8107,4 +8107,16 @@ CALL p();
81078107
drop procedure p;
81088108
drop view v;
81098109
drop table t, tmp_t;
8110+
#
8111+
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
8112+
#
8113+
CREATE TABLE t1 (i INT);
8114+
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
8115+
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
8116+
REPLACE INTO v1 VALUES (f1());
8117+
ERROR HY000: The target table v1 of the INSERT is not insertable-into
8118+
SET @aux = f1();
8119+
DROP FUNCTION f1;
8120+
DROP VIEW v1;
8121+
DROP TABLE t1;
81108122
#End of 10.1 tests

mysql-test/r/trigger.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,3 +2290,20 @@ INSERT INTO t1 VALUES ('a');
22902290
ERROR 22001: Data too long for column 'c' at row 1
22912291
DROP TRIGGER t1_bi;
22922292
DROP TABLE t1;
2293+
#
2294+
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
2295+
#
2296+
CREATE TABLE t1 (i INT);
2297+
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
2298+
CREATE TABLE t2 (a int);
2299+
CREATE TABLE t3 (a int);
2300+
create trigger trg after insert on t2 for each row
2301+
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
2302+
drop table t1;
2303+
insert into t2 value (2);
2304+
ERROR 42S02: Table 'test.t1' doesn't exist
2305+
CREATE TABLE t1 (i INT);
2306+
insert into t2 value (2);
2307+
DROP VIEW v1;
2308+
DROP TABLE t1,t2,t3;
2309+
End of 10.1 tests.

mysql-test/t/sp.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9588,4 +9588,21 @@ drop procedure p;
95889588
drop view v;
95899589
drop table t, tmp_t;
95909590

9591+
9592+
--echo #
9593+
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
9594+
--echo #
9595+
CREATE TABLE t1 (i INT);
9596+
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
9597+
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
9598+
9599+
--error ER_NON_INSERTABLE_TABLE
9600+
REPLACE INTO v1 VALUES (f1());
9601+
SET @aux = f1();
9602+
9603+
# Cleanup
9604+
DROP FUNCTION f1;
9605+
DROP VIEW v1;
9606+
DROP TABLE t1;
9607+
95919608
--echo #End of 10.1 tests

mysql-test/t/trigger.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,3 +2634,27 @@ INSERT INTO t1 VALUES ('a');
26342634
DROP TRIGGER t1_bi;
26352635
DROP TABLE t1;
26362636

2637+
--echo #
2638+
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
2639+
--echo #
2640+
2641+
CREATE TABLE t1 (i INT);
2642+
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
2643+
CREATE TABLE t2 (a int);
2644+
CREATE TABLE t3 (a int);
2645+
2646+
create trigger trg after insert on t2 for each row
2647+
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
2648+
2649+
drop table t1;
2650+
2651+
--error ER_NO_SUCH_TABLE
2652+
insert into t2 value (2);
2653+
CREATE TABLE t1 (i INT);
2654+
insert into t2 value (2);
2655+
2656+
DROP VIEW v1;
2657+
DROP TABLE t1,t2,t3;
2658+
2659+
2660+
--echo End of 10.1 tests.

sql/sp_head.cc

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
11361136
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
11371137
DBUG_RETURN(TRUE);
11381138

1139+
/*
1140+
Normally the counter is not reset between parsing and first execution,
1141+
but it is possible in case of error to have parsing on one CALL and
1142+
first execution (where VIEW will be parsed and added). So we store the
1143+
counter after parsing and restore it before execution just to avoid
1144+
repeating SELECT numbers.
1145+
1146+
Other problem is that it can be more SELECTs parsed in case of fixing
1147+
error causes previous interruption of the SP. So it is save not just
1148+
assign old value but add it.
1149+
*/
1150+
thd->select_number+= m_select_number;
1151+
11391152
/* init per-instruction memroot */
11401153
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
11411154

@@ -1469,6 +1482,16 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
14691482
m_recursion_level + 1));
14701483
m_first_instance->m_first_free_instance= this;
14711484

1485+
/*
1486+
This execution of the SP was aborted with an error (e.g. "Table not
1487+
found"). However it might still have consumed some numbers from the
1488+
thd->select_number counter. The next sp->exec() call must not use the
1489+
consumed numbers, so we remember the first free number (We know that
1490+
nobody will use it as this execution has stopped with an error).
1491+
*/
1492+
if (err_status)
1493+
set_select_number(thd->select_number);
1494+
14721495
DBUG_RETURN(err_status);
14731496
}
14741497

@@ -2099,26 +2122,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
20992122

21002123
if (!err_status)
21012124
{
2102-
/*
2103-
Normally the counter is not reset between parsing and first execution,
2104-
but it is possible in case of error to have parsing on one CALL and
2105-
first execution (where VIEW will be parsed and added). So we store the
2106-
counter after parsing and restore it before execution just to avoid
2107-
repeating SELECT numbers.
2108-
*/
2109-
thd->select_number= m_select_number;
2110-
21112125
err_status= execute(thd, TRUE);
2112-
DBUG_PRINT("info", ("execute returned %d", (int) err_status));
2113-
/*
2114-
This execution of the SP was aborted with an error (e.g. "Table not
2115-
found"). However it might still have consumed some numbers from the
2116-
thd->select_number counter. The next sp->exec() call must not use the
2117-
consumed numbers, so we remember the first free number (We know that
2118-
nobody will use it as this execution has stopped with an error).
2119-
*/
2120-
if (err_status)
2121-
set_select_number(thd->select_number);
21222126
}
21232127

21242128
if (save_log_general)

0 commit comments

Comments
 (0)