From 4fc9dc84b017cf9f30585bcdef0663f9425fe460 Mon Sep 17 00:00:00 2001
From: Oleksandr Byelkin <sanja@mariadb.com>
Date: Fri, 18 Apr 2025 12:14:23 +0200
Subject: [PATCH] MDEV-32086 (part 2) Server crash when inserting from derived 
 table containing insert target table

Get rid of need of matherialization for usual INSERT (cache results in
Item_cache* if needed)

- subqueries in VALUE do not see new records in the table we are
  inserting to
- subqueries in RETIRNING prohibited to use the table we are inserting to

Changes:
- subselect_elimination.result and subselect_elimination.test files
are not presented so skip those changes.

CVE: CVE-2023-52969 and CVE-2023-52970
Upstream-Status: Backport [https://github.com/MariaDB/server/commit/4fc9dc84b017cf9f30585bcdef0663f9425fe460]

Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
 mysql-test/main/insert.result                 |  72 +++++++-
 mysql-test/main/insert.test                   |  56 +++++-
 mysql-test/main/insert_returning.result       |   2 +
 mysql-test/main/insert_returning.test         |   2 +
 mysql-test/main/lowercase_view.result         |  12 --
 mysql-test/main/lowercase_view.test           |  12 --
 mysql-test/main/merge.result                  |  17 +-
 mysql-test/main/merge.test                    |  17 +-
 mysql-test/main/subselect.result              |  20 ++-
 mysql-test/main/subselect.test                |  10 +-
 .../main/subselect_no_exists_to_in.result     |  20 ++-
 mysql-test/main/subselect_no_mat.result       |  20 ++-
 mysql-test/main/subselect_no_opts.result      |  20 ++-
 mysql-test/main/subselect_no_scache.result    |  20 ++-
 mysql-test/main/subselect_no_semijoin.result  |  20 ++-
 mysql-test/main/view.result                   |  49 ++++--
 mysql-test/main/view.test                     |  30 ++--
 mysql-test/suite/sql_sequence/other.result    |   1 -
 mysql-test/suite/sql_sequence/other.test      |   1 -
 sql/item.h                                    |  12 ++
 sql/item_subselect.cc                         |  24 +++
 sql/item_subselect.h                          |   1 +
 sql/sql_base.cc                               |  86 +++++++---
 sql/sql_base.h                                |   3 +-
 sql/sql_insert.cc                             | 101 +++++++++--
 sql/sql_insert.h                              |   2 +-
 sql/sql_lex.cc                                |  42 +++++
 sql/sql_lex.h                                 |   4 +
 sql/sql_prepare.cc                            |   4 +-
 sql/table.h                                   |   2 +
 tests/mysql_client_test.c                     | 159 ++++++++++++++++++
 31 files changed, 682 insertions(+), 159 deletions(-)

diff --git a/mysql-test/main/insert.result b/mysql-test/main/insert.result
index 586dbbff..49ebd740 100644
--- a/mysql-test/main/insert.result
+++ b/mysql-test/main/insert.result
@@ -806,5 +806,75 @@ a
 8
 drop table t1;
 #
-# End of 10.5 tests
+# MDEV-32086 Server crash when inserting from derived table containing insert target table
+# (part 2)
 #
+create table t1 (pk int, id int);
+insert into t1 values (2,2), (3,3), (4,4);
+select * from t1;
+pk	id
+2	2
+3	3
+4	4
+select 101+count(*)
+from
+(
+select dt2.id
+from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id<1000;
+101+count(*)
+104
+prepare s from '
+insert into t1 values(
+  (select 101+count(*)
+   from
+   (
+      select dt2.id
+      from (select id from t1) dt2, t1 t where t.id=dt2.id
+   ) dt
+   where dt.id<1000
+  ), 123
+)
+';
+execute s;
+select * from t1;
+pk	id
+2	2
+3	3
+4	4
+104	123
+select 101+count(*)
+from
+(
+select dt2.id
+from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id<1000;
+101+count(*)
+105
+execute s;
+select * from t1;
+pk	id
+2	2
+3	3
+4	4
+104	123
+105	123
+drop table t1;
+#
+# Try this: INSERT INTO t1 VALUES ... reference to t1
+#           RETURNING (subquery not touching t1)
+create table t1 (a int, b int);
+create table t2 (a int, b int);
+# This is accepted:
+insert into t1 (a) values 
+(3),
+((select max(a) from t1)) 
+returning 
+a, b, (select max(a) from t2);
+a	b	(select max(a) from t2)
+3	NULL	NULL
+NULL	NULL	NULL
+drop table t1,t2;
+# End of 10.5 tests
diff --git a/mysql-test/main/insert.test b/mysql-test/main/insert.test
index e5cb2bac..c1661c27 100644
--- a/mysql-test/main/insert.test
+++ b/mysql-test/main/insert.test
@@ -667,5 +667,59 @@ select * from t1;
 drop table t1;
 
 --echo #
---echo # End of 10.5 tests
+--echo # MDEV-32086 Server crash when inserting from derived table containing insert target table
+--echo # (part 2)
 --echo #
+
+create table t1 (pk int, id int);
+insert into t1 values (2,2), (3,3), (4,4);
+select * from t1;
+select 101+count(*)
+   from
+   (
+      select dt2.id
+      from (select id from t1) dt2, t1 t where t.id=dt2.id
+   ) dt
+   where dt.id<1000;
+prepare s from '
+insert into t1 values(
+  (select 101+count(*)
+   from
+   (
+      select dt2.id
+      from (select id from t1) dt2, t1 t where t.id=dt2.id
+   ) dt
+   where dt.id<1000
+  ), 123
+)
+';
+execute s;
+select * from t1;
+select 101+count(*)
+   from
+   (
+      select dt2.id
+      from (select id from t1) dt2, t1 t where t.id=dt2.id
+   ) dt
+   where dt.id<1000;
+execute s;
+select * from t1;
+
+drop table t1;
+
+--echo #
+--echo # Try this: INSERT INTO t1 VALUES ... reference to t1
+--echo #           RETURNING (subquery not touching t1)
+create table t1 (a int, b int);
+create table t2 (a int, b int);
+
+--echo # This is accepted:
+insert into t1 (a) values 
+  (3),
+  ((select max(a) from t1)) 
+returning 
+  a, b, (select max(a) from t2);
+
+drop table t1,t2;
+
+--echo # End of 10.5 tests
diff --git a/mysql-test/main/insert_returning.result b/mysql-test/main/insert_returning.result
index 1976c1ca..d05c5704 100644
--- a/mysql-test/main/insert_returning.result
+++ b/mysql-test/main/insert_returning.result
@@ -488,6 +488,8 @@ t1 WHERE id1=1)
 5	6
 INSERT INTO t2(id2,val2) VALUES(5,'f') RETURNING (SELECT id2 FROM t2);
 ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+INSERT INTO t2(id2,val2) VALUES(5,'f') RETURNING (SELECT 1 UNION SELECT id2 FROM t2);
+ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t2 (id2, val2) VALUES (6,'f') RETURNING t1.*;
 ERROR 42S02: Unknown table 'test.t1'
 #
diff --git a/mysql-test/main/insert_returning.test b/mysql-test/main/insert_returning.test
index 837d61d2..c2ad613a 100644
--- a/mysql-test/main/insert_returning.test
+++ b/mysql-test/main/insert_returning.test
@@ -199,6 +199,8 @@ INSERT INTO t2(id2,val2) VALUES(5,'e') RETURNING id2, (SELECT id1+id2 FROM
 t1 WHERE id1=1);
 --error ER_UPDATE_TABLE_USED
 INSERT INTO t2(id2,val2) VALUES(5,'f') RETURNING (SELECT id2 FROM t2);
+--error ER_UPDATE_TABLE_USED
+INSERT INTO t2(id2,val2) VALUES(5,'f') RETURNING (SELECT 1 UNION SELECT id2 FROM t2);
 --error ER_BAD_TABLE_ERROR
 INSERT INTO t2 (id2, val2) VALUES (6,'f') RETURNING t1.*;
 
diff --git a/mysql-test/main/lowercase_view.result b/mysql-test/main/lowercase_view.result
index af53f678..845df4d6 100644
--- a/mysql-test/main/lowercase_view.result
+++ b/mysql-test/main/lowercase_view.result
@@ -16,29 +16,17 @@ create view v1Aa as select * from t1aA;
 create view v2aA as select * from v1aA;
 create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1;
 insert into v2Aa values ((select max(col1) from v1aA));
-ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2Aa'
 insert into t1aA values ((select max(col1) from v1Aa));
-ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 't1aA'
 insert into v2aA values ((select max(col1) from v1aA));
-ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table 'v2aA'
 insert into v2Aa values ((select max(col1) from t1Aa));
-ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 'v2Aa'
 insert into t1aA values ((select max(col1) from t1Aa));
-ERROR HY000: Table 't1aA' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into v2aA values ((select max(col1) from t1aA));
-ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v2aA'
 insert into v2Aa values ((select max(col1) from v2aA));
-ERROR HY000: Table 'v2Aa' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into t1Aa values ((select max(col1) from v2Aa));
-ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 't1Aa'
 insert into v2aA values ((select max(col1) from v2Aa));
-ERROR HY000: Table 'v2aA' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into v3Aa (col1) values ((select max(col1) from v1Aa));
-ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 'v3Aa'
 insert into v3aA (col1) values ((select max(col1) from t1aA));
-ERROR HY000: The definition of table 'v3aA' prevents operation INSERT on table 'v3aA'
 insert into v3Aa (col1) values ((select max(col1) from v2aA));
-ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v3Aa'
 drop view v3aA,v2Aa,v1aA;
 drop table t1Aa,t2Aa;
 create table t1Aa (col1 int);
diff --git a/mysql-test/main/lowercase_view.test b/mysql-test/main/lowercase_view.test
index cdd0256d..52aae7b2 100644
--- a/mysql-test/main/lowercase_view.test
+++ b/mysql-test/main/lowercase_view.test
@@ -23,29 +23,17 @@ create table t2aA (col1 int);
 create view v1Aa as select * from t1aA;
 create view v2aA as select * from v1aA;
 create view v3Aa as select v2Aa.col1 from v2aA,t2Aa where v2Aa.col1 = t2aA.col1;
--- error 1443
 insert into v2Aa values ((select max(col1) from v1aA));
--- error 1443
 insert into t1aA values ((select max(col1) from v1Aa));
--- error 1443
 insert into v2aA values ((select max(col1) from v1aA));
--- error 1443
 insert into v2Aa values ((select max(col1) from t1Aa));
--- error 1093
 insert into t1aA values ((select max(col1) from t1Aa));
--- error 1443
 insert into v2aA values ((select max(col1) from t1aA));
--- error 1093
 insert into v2Aa values ((select max(col1) from v2aA));
--- error 1443
 insert into t1Aa values ((select max(col1) from v2Aa));
--- error 1093
 insert into v2aA values ((select max(col1) from v2Aa));
--- error 1443
 insert into v3Aa (col1) values ((select max(col1) from v1Aa));
--- error 1443
 insert into v3aA (col1) values ((select max(col1) from t1aA));
--- error 1443
 insert into v3Aa (col1) values ((select max(col1) from v2aA));
 drop view v3aA,v2Aa,v1aA;
 drop table t1Aa,t2Aa;
diff --git a/mysql-test/main/merge.result b/mysql-test/main/merge.result
index 1e671e25..d10f0b67 100644
--- a/mysql-test/main/merge.result
+++ b/mysql-test/main/merge.result
@@ -3689,33 +3689,22 @@ insert into tmp (b) values (1);
 insert into t1 (a) values (1);
 insert into t3 (b) values (1);
 insert into m1 (a) values ((select max(a) from m1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from m2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t3, m1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t3, m2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t3, t1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from t3, t2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from tmp, m1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from tmp, m2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from tmp, t1));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from tmp, t2));
-ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into m1 (a) values ((select max(a) from v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'
 insert into m1 (a) values ((select max(a) from tmp, v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'
+select count(*) from m1;
+count(*)
+15
 drop view v1;
 drop temporary table tmp;
 drop table t1, t2, t3, m1, m2;
diff --git a/mysql-test/main/merge.test b/mysql-test/main/merge.test
index 99cce370..9e76515c 100644
--- a/mysql-test/main/merge.test
+++ b/mysql-test/main/merge.test
@@ -2706,37 +2706,24 @@ insert into tmp (b) values (1);
 
 insert into t1 (a) values (1);
 insert into t3 (b) values (1);
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from m1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from m2));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t2));
 
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t3, m1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t3, m2));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t3, t1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from t3, t2));
 
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from tmp, m1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from tmp, m2));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from tmp, t1));
---error ER_UPDATE_TABLE_USED
 insert into m1 (a) values ((select max(a) from tmp, t2));
- 
---error ER_VIEW_PREVENT_UPDATE
+
 insert into m1 (a) values ((select max(a) from v1));
---error ER_VIEW_PREVENT_UPDATE
 insert into m1 (a) values ((select max(a) from tmp, v1));
+select count(*) from m1;
 
 
 drop view v1;
diff --git a/mysql-test/main/subselect.result b/mysql-test/main/subselect.result
index 4209e2bc..dcbc2023 100644
--- a/mysql-test/main/subselect.result
+++ b/mysql-test/main/subselect.result
@@ -653,22 +653,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -676,6 +678,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -685,6 +688,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -701,7 +705,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -769,13 +773,21 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
 2
+2
+2
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
 UPDATE t2 SET id=(SELECT * FROM t1);
diff --git a/mysql-test/main/subselect.test b/mysql-test/main/subselect.test
index be22169a..f4394f08 100644
--- a/mysql-test/main/subselect.test
+++ b/mysql-test/main/subselect.test
@@ -400,7 +400,6 @@ create table t2 (a int) ENGINE=MyISAM;
 create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
--- error ER_UPDATE_TABLE_USED
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
 -- error ER_SUBQUERY_NO_1_ROW
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
@@ -435,7 +434,7 @@ create table t3 (a int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 select * from t1;
--- error ER_UPDATE_TABLE_USED
+-- error ER_BAD_NULL_ERROR
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
 -- error ER_SUBQUERY_NO_1_ROW
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
@@ -475,10 +474,13 @@ EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
 --disable_prepare_warnings
 SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3);
 SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
--- error ER_UPDATE_TABLE_USED
+-- error ER_SUBQUERY_NO_1_ROW
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
--- error ER_UPDATE_TABLE_USED
+-- error ER_SUBQUERY_NO_1_ROW
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
+select * from t2;
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
diff --git a/mysql-test/main/subselect_no_exists_to_in.result b/mysql-test/main/subselect_no_exists_to_in.result
index e32e6007..5c9e493a 100644
--- a/mysql-test/main/subselect_no_exists_to_in.result
+++ b/mysql-test/main/subselect_no_exists_to_in.result
@@ -657,22 +657,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -680,6 +682,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -689,6 +692,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -705,7 +709,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -773,9 +777,17 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+2
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
diff --git a/mysql-test/main/subselect_no_mat.result b/mysql-test/main/subselect_no_mat.result
index 07755a51..8c24edcc 100644
--- a/mysql-test/main/subselect_no_mat.result
+++ b/mysql-test/main/subselect_no_mat.result
@@ -660,22 +660,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -683,6 +685,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -692,6 +695,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -708,7 +712,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -776,13 +780,21 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
 2
+2
+2
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
 UPDATE t2 SET id=(SELECT * FROM t1);
diff --git a/mysql-test/main/subselect_no_opts.result b/mysql-test/main/subselect_no_opts.result
index 15688fc1..897ec5be 100644
--- a/mysql-test/main/subselect_no_opts.result
+++ b/mysql-test/main/subselect_no_opts.result
@@ -656,22 +656,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -679,6 +681,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -688,6 +691,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -704,7 +708,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -772,13 +776,21 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
 2
+2
+2
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
 UPDATE t2 SET id=(SELECT * FROM t1);
diff --git a/mysql-test/main/subselect_no_scache.result b/mysql-test/main/subselect_no_scache.result
index e3bdddbf..df43d4e5 100644
--- a/mysql-test/main/subselect_no_scache.result
+++ b/mysql-test/main/subselect_no_scache.result
@@ -659,22 +659,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -682,6 +684,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -691,6 +694,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -707,7 +711,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -775,13 +779,21 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
 2
+2
+2
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
 UPDATE t2 SET id=(SELECT * FROM t1);
diff --git a/mysql-test/main/subselect_no_semijoin.result b/mysql-test/main/subselect_no_semijoin.result
index a06a4aef..b43cf744 100644
--- a/mysql-test/main/subselect_no_semijoin.result
+++ b/mysql-test/main/subselect_no_semijoin.result
@@ -656,22 +656,24 @@ create table t3 (b int);
 insert into t2 values (1);
 insert into t3 values (1),(2);
 INSERT INTO t1 (x) VALUES ((SELECT x FROM t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 INSERT INTO t1 (x) VALUES ((SELECT b FROM t3));
 ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t1 (x) VALUES ((SELECT a FROM t2));
 select * from t1;
 x
+NULL
 1
 insert into t2 values (1);
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -679,6 +681,7 @@ x
 INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -688,6 +691,7 @@ x
 INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
 select * from t1;
 x
+NULL
 1
 2
 3
@@ -704,7 +708,7 @@ insert into t3 values (1),(2);
 select * from t1;
 x	y
 replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 23000: Column 'x' cannot be null
 replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2));
 ERROR 21000: Subquery returns more than 1 row
 replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2));
@@ -772,13 +776,21 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2);
 id
 2
 INSERT INTO t2 VALUES ((SELECT * FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
 INSERT INTO t2 VALUES ((SELECT id FROM t2));
-ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data
+ERROR 21000: Subquery returns more than 1 row
+select * from t2;
+id
+1
+2
+INSERT INTO t2 VALUES ((SELECT count(*) FROM t2));
+INSERT INTO t2 VALUES ((SELECT max(id) FROM t2));
 SELECT * FROM t2;
 id
 1
 2
+2
+2
 CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) ENGINE=MyISAM CHARSET=latin1;
 INSERT INTO t1 values (1),(1);
 UPDATE t2 SET id=(SELECT * FROM t1);
diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result
index 69e850cd..41ec8f43 100644
--- a/mysql-test/main/view.result
+++ b/mysql-test/main/view.result
@@ -944,31 +944,19 @@ create view v1 as select * from t1;
 create view v2 as select * from v1;
 create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
 insert into v2 values ((select max(col1) from v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v2'
 insert into t1 values ((select max(col1) from v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 't1'
 insert into v2 values ((select max(col1) from v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v2'
 insert into v2 values ((select max(col1) from t1));
-ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'
 insert into t1 values ((select max(col1) from t1));
-ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into v2 values ((select max(col1) from t1));
-ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'
 insert into v2 values ((select max(col1) from v2));
-ERROR HY000: Table 'v2' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into t1 values ((select max(col1) from v2));
-ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 't1'
 insert into v2 values ((select max(col1) from v2));
-ERROR HY000: Table 'v2' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into v3 (col1) values ((select max(col1) from v1));
-ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v3'
 insert into v3 (col1) values ((select max(col1) from t1));
-ERROR HY000: The definition of table 'v3' prevents operation INSERT on table 'v3'
 insert into v3 (col1) values ((select max(col1) from v2));
-ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'
-insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
-ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2 LIMIT 1));
+ERROR 22003: Out of range value for column 'col1' at row 2
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
 insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
 ERROR 23000: Column 'col1' cannot be null
@@ -978,6 +966,18 @@ insert into t1 (col1) values ((select max(col1) from v4));
 select * from t1;
 col1
 NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
 1
 2
 3
@@ -1332,9 +1332,26 @@ create view v3 as select * from t1 where 20 < (select (s1) from v2);
 insert into v3 values (30);
 ERROR HY000: The target table v3 of the INSERT is not insertable-into
 create view v4 as select * from v2 where 20 < (select (s1) from t1);
+select * from t1;
+s1
 insert into v4 values (30);
-ERROR HY000: The target table v4 of the INSERT is not insertable-into
-drop view v4, v3, v2, v1;
+select * from t1;
+s1
+30
+create view v5 as select * from v2 where s1 < (select min(s1) from t1) WITH CHECK OPTION;
+# can't insert only less then minimum
+insert into v5 values (40);
+ERROR 44000: CHECK OPTION failed `test`.`v5`
+# allow insert the new minimum
+insert into v5 values (10);
+# always emply view (can't be something less than minimum)
+select * from v5;
+s1
+select * from t1;
+s1
+30
+10
+drop view v5, v4, v3, v2, v1;
 drop table t1;
 create table t1 (a int);
 create view v1 as select * from t1;
diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test
index f32b148b..4e1dc911 100644
--- a/mysql-test/main/view.test
+++ b/mysql-test/main/view.test
@@ -865,33 +865,21 @@ create table t3 (col1 datetime not null);
 create view v1 as select * from t1;
 create view v2 as select * from v1;
 create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
--- error ER_VIEW_PREVENT_UPDATE
 insert into v2 values ((select max(col1) from v1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into t1 values ((select max(col1) from v1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v2 values ((select max(col1) from v1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v2 values ((select max(col1) from t1));
--- error ER_UPDATE_TABLE_USED
 insert into t1 values ((select max(col1) from t1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v2 values ((select max(col1) from t1));
--- error ER_UPDATE_TABLE_USED
 insert into v2 values ((select max(col1) from v2));
--- error ER_VIEW_PREVENT_UPDATE
 insert into t1 values ((select max(col1) from v2));
--- error ER_UPDATE_TABLE_USED
 insert into v2 values ((select max(col1) from v2));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v3 (col1) values ((select max(col1) from v1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v3 (col1) values ((select max(col1) from t1));
--- error ER_VIEW_PREVENT_UPDATE
 insert into v3 (col1) values ((select max(col1) from v2));
 # check with TZ tables in list
--- error ER_VIEW_PREVENT_UPDATE
-insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
+--error ER_WARN_DATA_OUT_OF_RANGE
+insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2 LIMIT 1));
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
 -- error ER_BAD_NULL_ERROR
 insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
@@ -1209,9 +1197,19 @@ create view v3 as select * from t1 where 20 < (select (s1) from v2);
 -- error ER_NON_INSERTABLE_TABLE
 insert into v3 values (30);
 create view v4 as select * from v2 where 20 < (select (s1) from t1);
--- error ER_NON_INSERTABLE_TABLE
+select * from t1;
 insert into v4 values (30);
-drop view v4, v3, v2, v1;
+select * from t1;
+create view v5 as select * from v2 where s1 < (select min(s1) from t1) WITH CHECK OPTION;
+--echo # can't insert only less then minimum
+--error ER_VIEW_CHECK_FAILED
+insert into v5 values (40);
+--echo # allow insert the new minimum
+insert into v5 values (10);
+--echo # always emply view (can't be something less than minimum)
+select * from v5;
+select * from t1;
+drop view v5, v4, v3, v2, v1;
 drop table t1;
 
 #
diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result
index d237be63..a2a93d11 100644
--- a/mysql-test/suite/sql_sequence/other.result
+++ b/mysql-test/suite/sql_sequence/other.result
@@ -48,7 +48,6 @@ create sequence s2;
 insert into s1 (next_not_cached_value, minimum_value) values (100,1000);
 ERROR HY000: Field 'maximum_value' doesn't have a default value
 insert into s1 values (next value for s1, 1,9223372036854775806,1,1,1000,0,0);
-ERROR HY000: Table 's1' is specified twice, both as a target for 'INSERT' and as a separate source for data
 insert into s1 values(1000,9223372036854775806,1,1,1,1000,0,0);
 ERROR HY000: Sequence 'test.s1' has out of range value for options
 insert into s1 values(0,9223372036854775806,1,1,1,1000,0,0);
diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test
index 639cc5c3..69d51b3a 100644
--- a/mysql-test/suite/sql_sequence/other.test
+++ b/mysql-test/suite/sql_sequence/other.test
@@ -36,7 +36,6 @@ create sequence s1;
 create sequence s2;
 --error ER_NO_DEFAULT_FOR_FIELD
 insert into s1 (next_not_cached_value, minimum_value) values (100,1000);
---error ER_UPDATE_TABLE_USED
 insert into s1 values (next value for s1, 1,9223372036854775806,1,1,1000,0,0);
 --error ER_SEQUENCE_INVALID_DATA
 insert into s1 values(1000,9223372036854775806,1,1,1,1000,0,0);
diff --git a/sql/item.h b/sql/item.h
index 6c3b73df..cec075b4 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -753,6 +753,17 @@ class Item_const
   virtual const String *const_ptr_string() const { return NULL; }
 };
 
+struct subselect_table_finder_param
+{
+  THD *thd;
+  /*
+    We're searching for different TABLE_LIST objects referring to the same
+    table as this one
+  */
+  const TABLE_LIST *find;
+  /* NUL - not found, ERROR_TABLE - search error, or the found table reference */
+  TABLE_LIST *dup;
+};
 
 /****************************************************************************/
 
@@ -2216,6 +2227,7 @@ class Item :public Value_source,
     set_extraction_flag(*(int16*)arg);
     return 0;
   }
+  virtual bool subselect_table_finder_processor(void *arg) { return 0; };
 
   /**
     Check db/table_name if they defined in item and match arg values
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f509e00b..4d579f09 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -7001,3 +7001,27 @@ void Item_subselect::init_expr_cache_tracker(THD *thd)
   DBUG_ASSERT(expr_cache->type() == Item::EXPR_CACHE_ITEM);
   node->cache_tracker= ((Item_cache_wrapper *)expr_cache)->init_tracker(qw->mem_root);
 }
+
+
+/*
+  Check if somewhere inside this subselect we read the table. This means a
+  full read "(SELECT ... FROM tbl)", outside reference to tbl.column does not
+  count
+*/
+
+bool
+Item_subselect::subselect_table_finder_processor(void *arg)
+{
+  subselect_table_finder_param *param= (subselect_table_finder_param *)arg;
+  for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+  {
+    TABLE_LIST *dup;
+    if ((dup= sl->find_table(param->thd, &param->find->db,
+                             &param->find->table_name)))
+    {
+      param->dup= dup;
+      return TRUE;
+    }
+  }
+  return FALSE;
+};
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index fdd0333a..b03ad835 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -270,6 +270,7 @@ class Item_subselect :public Item_result_field,
   {
     return TRUE;
   }
+  bool subselect_table_finder_processor(void *arg) override;
 
   void register_as_with_rec_ref(With_element *with_elem);
   void init_expr_cache_tracker(THD *thd);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 15a9882b..6374d0be 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -19,6 +19,7 @@
 
 #include "mariadb.h"
 #include "sql_base.h"                           // setup_table_map
+#include "sql_list.h"
 #include "sql_priv.h"
 #include "unireg.h"
 #include "debug_sync.h"
@@ -1114,7 +1115,6 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
   t_name= &table->table_name;
   t_alias= &table->alias;
 
-retry:
   DBUG_PRINT("info", ("real table: %s.%s", d_name->str, t_name->str));
   for (TABLE_LIST *tl= table_list; tl ; tl= tl->next_global, res= 0)
   {
@@ -1176,37 +1176,52 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
     DBUG_PRINT("info",
                ("found same copy of table or table which we should skip"));
   }
-  /*
-     If we've found a duplicate in a derived table, try to work around that.
-
-     For INSERT...SELECT, do not do any workarounds, return the duplicate. The
-     caller will enable buffering to handle this.
-  */
-  if (res && res->belong_to_derived &&
-      !(check_flag & CHECK_DUP_FOR_INSERT_SELECT))
-  {
-    /*
-      We come here for queries like this:
+  DBUG_RETURN(res);
+}
 
-      INSERT INTO t1 VALUES ((SELECT tmp.a FROM (select * FROM t1)));
-      DELETE FROM t1 WHERE ( ... (SELECT ... FROM t1) ) ;
 
-      Try to fix by materializing the derived table
-    */
-    TABLE_LIST *derived=  res->belong_to_derived;
-    if (derived->is_merged_derived() && !derived->derived->is_excluded())
+TABLE_LIST* unique_table_in_select_list(THD *thd, TABLE_LIST *table, SELECT_LEX *sel)
+{
+  subselect_table_finder_param param= {thd, table, NULL};
+  List_iterator_fast<Item> it(sel->item_list);
+  Item *item;
+  while ((item= it++))
+  {
+    if (item->walk(&Item::subselect_table_finder_processor, FALSE, &param))
     {
-      DBUG_PRINT("info",
-                 ("convert merged to materialization to resolve the conflict"));
-      derived->change_refs_to_fields();
-      derived->set_materialized_derived();
-      goto retry;
+      if (param.dup == NULL)
+        return ERROR_TABLE;
+      return param.dup;
     }
+    DBUG_ASSERT(param.dup == NULL);
   }
-  DBUG_RETURN(res);
+  return NULL;
 }
 
 
+typedef TABLE_LIST* (*find_table_callback)(THD *thd, TABLE_LIST *table,
+                                           TABLE_LIST *table_list,
+                                           uint check_flag, SELECT_LEX *sel);
+
+static
+TABLE_LIST*
+find_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+           uint check_flag, SELECT_LEX *sel, find_table_callback callback );
+
+TABLE_LIST* unique_table_callback(THD *thd, TABLE_LIST *table,
+                                  TABLE_LIST *table_list,
+                                  uint check_flag, SELECT_LEX *sel)
+{
+  return find_dup_table(thd, table, table_list, check_flag);
+}
+
+
+TABLE_LIST* unique_in_sel_table_callback(THD *thd, TABLE_LIST *table,
+                                         TABLE_LIST *table_list,
+                                         uint check_flag, SELECT_LEX *sel)
+{
+  return unique_table_in_select_list(thd, table, sel);
+}
 /**
   Test that the subject table of INSERT/UPDATE/DELETE/CREATE
   or (in case of MyISAMMRG) one of its children are not used later
@@ -1225,6 +1240,25 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
 TABLE_LIST*
 unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
              uint check_flag)
+{
+  return find_table(thd, table, table_list, check_flag, NULL,
+                    &unique_table_callback);
+}
+
+
+TABLE_LIST*
+unique_table_in_insert_returning_subselect(THD *thd, TABLE_LIST *table, SELECT_LEX *sel)
+{
+  return find_table(thd, table, NULL, 0, sel,
+                    &unique_in_sel_table_callback);
+
+}
+
+
+static
+TABLE_LIST*
+find_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+           uint check_flag, SELECT_LEX *sel, find_table_callback callback )
 {
   TABLE_LIST *dup;
 
@@ -1256,12 +1290,12 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
       if (!tmp_parent)
         break;
 
-      if ((dup= find_dup_table(thd, child, child->next_global, check_flag)))
+      if ((dup= (*callback)(thd, child, child->next_global, check_flag, sel)))
         break;
     }
   }
   else
-    dup= find_dup_table(thd, table, table_list, check_flag);
+    dup= (*callback)(thd, table, table_list, check_flag, sel);
   return dup;
 }
 
diff --git a/sql/sql_base.h b/sql/sql_base.h
index da9b1575..6de4d2b8 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -72,7 +72,6 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
 #define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1
 #define CHECK_DUP_FOR_CREATE 2
 #define CHECK_DUP_SKIP_TEMP_TABLE 4
-#define CHECK_DUP_FOR_INSERT_SELECT 8
 
 uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
 TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
@@ -291,6 +290,8 @@ bool open_and_lock_internal_tables(TABLE *table, bool lock);
 bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
 int decide_logging_format(THD *thd, TABLE_LIST *tables);
 void close_thread_table(THD *thd, TABLE **table_ptr);
+TABLE_LIST*
+unique_table_in_insert_returning_subselect(THD *thd, TABLE_LIST *table, SELECT_LEX *sel);
 TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
                          uint check_flag);
 bool is_equal(const LEX_CSTRING *a, const LEX_CSTRING *b);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index d9813660..91bd6e93 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -57,6 +57,7 @@
 */
 
 #include "mariadb.h"                 /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_list.h"
 #include "sql_priv.h"
 #include "sql_insert.h"
 #include "sql_update.h"                         // compare_record
@@ -712,6 +713,8 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
   Name_resolution_context_state ctx_state;
   SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
   unsigned char *readbuff= NULL;
+  List<List_item> insert_values_cache;
+  bool cache_insert_values= FALSE;
 
 #ifndef EMBEDDED_LIBRARY
   char *query= thd->query();
@@ -769,7 +772,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
 
   if ((res= mysql_prepare_insert(thd, table_list, fields, values,
                                  update_fields, update_values, duplic, ignore,
-                                 &unused_conds, FALSE)))
+                                 &unused_conds, FALSE, &cache_insert_values)))
   {
     retval= thd->is_error();
     if (res < 0)
@@ -1019,8 +1022,41 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
   if (returning)
     fix_rownum_pointers(thd, thd->lex->returning(), &info.accepted_rows);
 
+  if (cache_insert_values)
+  {
+    insert_values_cache.empty();
+    while ((values= its++))
+    {
+      List<Item> *caches= new (thd->mem_root) List_item;
+      List_iterator_fast<Item> iv(*values);
+      Item *item;
+      if (caches == 0)
+      {
+        error= 1;
+        goto values_loop_end;
+      }
+      caches->empty();
+      while((item= iv++))
+      {
+        Item_cache *cache= item->get_cache(thd);
+        if (!cache)
+        {
+          error= 1;
+          goto values_loop_end;
+        }
+        cache->setup(thd, item);
+        caches->push_back(cache);
+      }
+      insert_values_cache.push_back(caches);
+    }
+    its.rewind();
+  }
+
   do
   {
+    List_iterator_fast<List_item> itc(insert_values_cache);
+    List_iterator_fast<List_item> *itr;
+
     DBUG_PRINT("info", ("iteration %llu", iteration));
     if (iteration && bulk_parameters_set(thd))
     {
@@ -1028,7 +1064,24 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
       goto values_loop_end;
     }
 
-    while ((values= its++))
+    if (cache_insert_values)
+    {
+      List_item *caches;
+      while ((caches= itc++))
+      {
+        List_iterator_fast<Item> ic(*caches);
+        Item_cache *cache;
+        while((cache= (Item_cache*) ic++))
+        {
+          cache->cache_value();
+        }
+      }
+      itc.rewind();
+      itr= &itc;
+    }
+    else
+      itr= &its;
+    while ((values= (*itr)++))
     {
       thd->get_stmt_da()->inc_current_row_for_warning();
       if (fields.elements || !value_count)
@@ -1148,7 +1201,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
         break;
       info.accepted_rows++;
     }
-    its.rewind();
+    itr->rewind();
     iteration++;
   } while (bulk_parameters_iterations(thd));
 
@@ -1620,6 +1673,7 @@ static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
     table_list          Global/local table list
     where               Where clause (for insert ... select)
     select_insert       TRUE if INSERT ... SELECT statement
+    cache_insert_values insert's VALUES(...) has to be pre-computed
 
   TODO (in far future)
     In cases of:
@@ -1642,7 +1696,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
                          List<Item> &update_fields, List<Item> &update_values,
                          enum_duplicates duplic, bool ignore,
                          COND **where,
-                         bool select_insert)
+                         bool select_insert, bool * const cache_insert_values)
 {
   SELECT_LEX *select_lex= thd->lex->first_select_lex();
   Name_resolution_context *context= &select_lex->context;
@@ -1743,11 +1797,12 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
 
   /*
     Check if we read from the same table we're inserting into.
-    Queries like INSERT INTO t1 VALUES ((SELECT ... FROM t1...)) are not
-    allowed.
+    Queries like INSERT INTO t1 VALUES ((SELECT ... FROM t1...)) have
+    to pre-compute the VALUES part.
+    Reading from the same table in the RETURNING clause is not allowed.
 
-    INSERT...SELECT is an exception: it will detect this case and use
-    buffering to handle it correctly.
+    INSERT...SELECT detects this case in select_insert::prepare and also
+    uses buffering to handle it correcly.
   */
   if (!select_insert)
   {
@@ -1756,10 +1811,30 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
     if ((duplicate= unique_table(thd, table_list, table_list->next_global,
                                  CHECK_DUP_ALLOW_DIFFERENT_ALIAS)))
     {
-      update_non_unique_table_error(table_list, "INSERT", duplicate);
-      DBUG_RETURN(1);
+     /*
+        This is INSERT INTO ... VALUES (...) and it must pre-compute the
+        values to be inserted.
+      */
+      (*cache_insert_values)= true;
     }
+    else
+      (*cache_insert_values)= false;
+
     select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds);
+
+    if ((*cache_insert_values) && thd->lex->has_returning())
+    {
+      // Check if the table we're inserting into is also in RETURNING clause
+      TABLE_LIST *dup=
+         unique_table_in_insert_returning_subselect(thd, table_list,
+                                                    thd->lex->returning());
+      if (dup)
+      {
+        if (dup != ERROR_TABLE)
+          update_non_unique_table_error(table_list, "INSERT", duplicate);
+        DBUG_RETURN(1);
+      }
+    }
   }
   /*
     Only call prepare_for_posistion() if we are not performing a DELAYED
@@ -3817,6 +3892,7 @@ int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
   int res;
   LEX *lex= thd->lex;
   SELECT_LEX *select_lex= lex->first_select_lex();
+  bool cache_insert_values= false;
   DBUG_ENTER("mysql_insert_select_prepare");
 
   /*
@@ -3827,7 +3903,7 @@ int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
   if ((res= mysql_prepare_insert(thd, lex->query_tables, lex->field_list, 0,
                                  lex->update_list, lex->value_list,
                                  lex->duplicates, lex->ignore,
-                                 &select_lex->where, TRUE)))
+                                 &select_lex->where, TRUE, &cache_insert_values)))
     DBUG_RETURN(res);
 
   /*
@@ -4029,8 +4105,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
     Is table which we are changing used somewhere in other parts of
     query
   */
-  if (unique_table(thd, table_list, table_list->next_global,
-                   CHECK_DUP_FOR_INSERT_SELECT))
+  if (unique_table(thd, table_list, table_list->next_global, 0))
   {
     /* Using same table for INSERT and SELECT */
     lex->current_select->options|= OPTION_BUFFER_RESULT;
diff --git a/sql/sql_insert.h b/sql/sql_insert.h
index 8b034c25..656da557 100644
--- a/sql/sql_insert.h
+++ b/sql/sql_insert.h
@@ -28,7 +28,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
                          List<Item> &update_fields,
                          List<Item> &update_values, enum_duplicates duplic,
                          bool ignore,
-                         COND **where, bool select_insert);
+                         COND **where, bool select_insert, bool * const cache_results);
 bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
                   List<List_item> &values, List<Item> &update_fields,
                   List<Item> &update_values, enum_duplicates flag,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b3aef010..51678f76 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -11872,3 +11872,45 @@ bool SELECT_LEX_UNIT::explainable() const
                derived->is_materialized_derived() :   // (3)
                false;
 }
+
+/**
+  Find the real table in prepared SELECT tree
+
+  NOTE: all SELECT must be prepared (to have leaf table list).
+
+  NOTE: it looks only for real tables (not view or derived)
+
+  @param thd          the current thread handle
+  @param db_name      name of db of the table to look for
+  @param db_name      name of db of the table to look for
+
+  @return first found table, NULL or ERROR_TABLE
+*/
+
+TABLE_LIST *SELECT_LEX::find_table(THD *thd,
+                                   const LEX_CSTRING *db_name,
+                                   const LEX_CSTRING *table_name)
+{
+  uchar buff[STACK_BUFF_ALLOC];                 // Max argument in function
+  if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
+    return NULL;
+
+  List_iterator_fast <TABLE_LIST> ti(leaf_tables);
+  TABLE_LIST *table;
+  while ((table= ti++))
+  {
+    if (cmp(&table->db, db_name) == 0 &&
+        cmp(&table->table_name, table_name) == 0)
+      return table;
+  }
+
+  for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit())
+  {
+    for (st_select_lex *sl= u->first_select(); sl; sl=sl->next_select())
+    {
+      if ((table= sl->find_table(thd, db_name, table_name)))
+        return table;
+    }
+  }
+  return NULL;
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9d2912c8..2300a772 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1641,6 +1641,10 @@ class st_select_lex: public st_select_lex_node
   void lex_start(LEX *plex);
   bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); }
   void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; }
+
+  TABLE_LIST *find_table(THD *thd,
+                         const LEX_CSTRING *db_name,
+                         const LEX_CSTRING *table_name);
 };
 typedef class st_select_lex SELECT_LEX;
 
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 65d515d3..ec5d1692 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1294,6 +1294,7 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
   THD *thd= stmt->thd;
   List_iterator_fast<List_item> its(values_list);
   List_item *values;
+  bool cache_results= FALSE;
   DBUG_ENTER("mysql_test_insert_common");
 
   if (insert_precheck(thd, table_list))
@@ -1326,7 +1327,8 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
 
     if (mysql_prepare_insert(thd, table_list, fields, values, update_fields,
                              update_values, duplic, ignore,
-                             &unused_conds, FALSE))
+                             &unused_conds, FALSE,
+                             &cache_results))
       goto error;
 
     value_count= values->elements;
diff --git a/sql/table.h b/sql/table.h
index d0f61eb0..5493412d 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2973,6 +2973,8 @@ struct TABLE_LIST
   ulong m_table_ref_version;
 };
 
+#define ERROR_TABLE  ((TABLE_LIST*) 0x1)
+
 class Item;
 
 /*
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 528eece5..0bcb1e98 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -21535,6 +21535,164 @@ static void test_mdev19838()
   rc = mysql_query(mysql, "drop table mdev19838");
   myquery(rc);
 }
+
+/* Server crash when inserting from derived table containing insert target table */
+static void test_mdev_32086()
+{
+  int        rc;
+  MYSQL_STMT *stmt_insert;
+  MYSQL_BIND bind[2];
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  unsigned int vals[] = { 123, 124};
+  unsigned int vals_array_len = 2;
+  const char *insert_stmt= "\
+insert into t1 values(\
+  (select 101+count(*)\
+   from\
+   (\
+      select dt2.id\
+      from (select id from t1) dt2, t1 t where t.id=dt2.id\
+   ) dt\
+   where dt.id<1000\
+  ), ?\
+)";
+
+  /* Set up test's environment */
+
+
+  rc= mysql_query(mysql, "create table t1 (pk int, id int);");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "insert into t1 values (2,2), (3,3), (4,4);");
+  myquery(rc);
+
+  stmt_insert = mysql_stmt_init(mysql);
+  if (!stmt_insert)
+  {
+    fprintf(stderr, "mysql_stmt_init failed: Error: %s\n",
+            mysql_error(mysql));
+    exit(1);
+  }
+
+  rc= mysql_stmt_prepare(stmt_insert, insert_stmt, strlen(insert_stmt));
+  if (rc)
+  {
+    fprintf(stderr, "mysql_stmt_prepare failed: %s\n",
+            mysql_stmt_error(stmt_insert));
+    exit(1);
+  }
+
+  memset(&bind[0], 0, sizeof(MYSQL_BIND));
+
+  bind[0].buffer_type= MYSQL_TYPE_LONG;
+  bind[0].buffer= vals;
+
+  rc= mysql_stmt_attr_set(stmt_insert, STMT_ATTR_ARRAY_SIZE, &vals_array_len);
+  if (rc)
+  {
+    fprintf(stderr, "mysql_stmt_prepare failed: %s\n",
+            mysql_stmt_error(stmt_insert));
+    exit(1);
+  }
+
+  rc= mysql_stmt_bind_param(stmt_insert, bind);
+  if (rc)
+  {
+    fprintf(stderr, "mysql_stmt_bind_param failed: %s\n",
+            mysql_stmt_error(stmt_insert));
+    exit(1);
+  }
+
+  rc= mysql_stmt_execute(stmt_insert);
+  if (rc)
+  {
+    fprintf(stderr, "mysql_stmt_execute failed: %s\n",
+            mysql_stmt_error(stmt_insert));
+    exit(1);
+  }
+
+  /*
+    pk	id
+    2	2
+    3	3
+    4	4
+    104	123
+    104	124
+   */
+  rc= mysql_query(mysql, "select * from t1");
+  if (rc)
+  {
+    fprintf(stderr, "Query failed: %s\n", mysql_error(mysql));
+  }
+  result= mysql_store_result(mysql);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 2 && atoi(row[1]) == 2);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 3 && atoi(row[1]) == 3);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 4 && atoi(row[1]) == 4);
+  row= mysql_fetch_row(result);
+  printf("\n %d, %d \n", atoi(row[0]), atoi(row[1]));
+  DIE_UNLESS(atoi(row[0]) == 104 && atoi(row[1]) == 123);
+  row= mysql_fetch_row(result);
+  printf("\n %d, %d \n", atoi(row[0]), atoi(row[1]));
+  DIE_UNLESS(atoi(row[0]) == 104 && atoi(row[1]) == 124);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(row == NULL);
+
+  mysql_free_result(result);
+
+  rc= mysql_stmt_execute(stmt_insert);
+  if (rc)
+  {
+    fprintf(stderr, "mysql_stmt_execute failed: %s\n",
+            mysql_stmt_error(stmt_insert));
+    exit(1);
+  }
+  /*
+    pk	id
+    2	2
+    3	3
+    4	4
+    104	123
+    104	124
+    106	123
+    106	124
+   */
+  rc= mysql_query(mysql, "select * from t1");
+  if (rc)
+  {
+    fprintf(stderr, "Query failed: %s\n", mysql_error(mysql));
+  }
+  result= mysql_store_result(mysql);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 2 && atoi(row[1]) == 2);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 3 && atoi(row[1]) == 3);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 4 && atoi(row[1]) == 4);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 104 && atoi(row[1]) == 123);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(atoi(row[0]) == 104 && atoi(row[1]) == 124);
+  row= mysql_fetch_row(result);
+  printf("\n %d, %d \n", atoi(row[0]), atoi(row[1]));
+  DIE_UNLESS(atoi(row[0]) == 106 && atoi(row[1]) == 123);
+  row= mysql_fetch_row(result);
+  printf("\n %d, %d \n", atoi(row[0]), atoi(row[1]));
+  DIE_UNLESS(atoi(row[0]) == 106 && atoi(row[1]) == 124);
+  row= mysql_fetch_row(result);
+  DIE_UNLESS(row == NULL);
+
+  mysql_free_result(result);
+
+  mysql_stmt_close(stmt_insert);
+
+  /* Clean up */
+  rc= mysql_query(mysql, "DROP TABLE t1");
+  myquery(rc);
+}
 #endif // EMBEDDED_LIBRARY
 
 
@@ -22102,6 +22260,7 @@ static struct my_tests_st my_tests[]= {
   { "test_explain_meta", test_explain_meta },
 #ifndef EMBEDDED_LIBRARY
   { "test_mdev19838", test_mdev19838 },
+  { "test_mdev_32086", test_mdev_32086 },
 #endif
   { "test_mdev_16128", test_mdev_16128 },
   { "test_mdev18408", test_mdev18408 },
-- 
2.40.0

