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
This commit is contained in:
Oleksandr Byelkin 2025-04-18 12:14:23 +02:00
parent 9b313d2de1
commit 4fc9dc84b0
33 changed files with 705 additions and 165 deletions

View File

@ -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

View File

@ -675,5 +675,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

View File

@ -498,6 +498,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'
#

View File

@ -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.*;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -2704,37 +2704,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;

View File

@ -679,22 +679,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
@ -702,6 +704,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -711,6 +714,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -727,7 +731,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));
@ -795,13 +799,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);

View File

@ -415,7 +415,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));
@ -450,7 +449,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));
@ -486,10 +485,13 @@ EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3);
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);

View File

@ -136,12 +136,22 @@ DROP TABLE t1;
# access within null pointer
CREATE TABLE x (x INT) ENGINE=InnoDB;
INSERT INTO x (x) VALUES (0);
select NULL IN (SELECT (SELECT x FROM (SELECT x FROM
(SELECT 0 IN (SELECT x=0 FROM (SELECT x FROM (SELECT (SELECT (SELECT (SELECT
(SELECT 0 AS x) FROM x AS x) IN (SELECT 0 AS x) AS x) FROM x AS x) IN
(SELECT x WHERE x=0) AS x FROM x AS x) AS x) AS x GROUP BY x) AS x FROM x) AS x)
AS x) IN (SELECT 0 AS x) AS x FROM x) as exp;
exp
NULL
INSERT INTO x (x) VALUES (x IN (SELECT (SELECT x FROM (SELECT x FROM
(SELECT 0 IN (SELECT x=0 FROM (SELECT x FROM (SELECT (SELECT (SELECT (SELECT
(SELECT 0 AS x) FROM x AS x) IN (SELECT 0 AS x) AS x) FROM x AS x) IN
(SELECT x WHERE x=0) AS x FROM x AS x) AS x) AS x GROUP BY x) AS x FROM x) AS x)
AS x) IN (SELECT 0 AS x) AS x FROM x));
ERROR HY000: Table 'x' is specified twice, both as a target for 'INSERT' and as a separate source for data
select * from x;
x
0
NULL
DROP TABLE x;
# MDEV-28622: Item_subselect eliminated flag set but Item still
# evaluated/used.

View File

@ -133,12 +133,17 @@ DROP TABLE t1;
CREATE TABLE x (x INT) ENGINE=InnoDB;
INSERT INTO x (x) VALUES (0);
--error ER_UPDATE_TABLE_USED
select NULL IN (SELECT (SELECT x FROM (SELECT x FROM
(SELECT 0 IN (SELECT x=0 FROM (SELECT x FROM (SELECT (SELECT (SELECT (SELECT
(SELECT 0 AS x) FROM x AS x) IN (SELECT 0 AS x) AS x) FROM x AS x) IN
(SELECT x WHERE x=0) AS x FROM x AS x) AS x) AS x GROUP BY x) AS x FROM x) AS x)
AS x) IN (SELECT 0 AS x) AS x FROM x) as exp;
INSERT INTO x (x) VALUES (x IN (SELECT (SELECT x FROM (SELECT x FROM
(SELECT 0 IN (SELECT x=0 FROM (SELECT x FROM (SELECT (SELECT (SELECT (SELECT
(SELECT 0 AS x) FROM x AS x) IN (SELECT 0 AS x) AS x) FROM x AS x) IN
(SELECT x WHERE x=0) AS x FROM x AS x) AS x) AS x GROUP BY x) AS x FROM x) AS x)
AS x) IN (SELECT 0 AS x) AS x FROM x));
select * from x;
DROP TABLE x;
--echo # MDEV-28622: Item_subselect eliminated flag set but Item still

View File

@ -683,22 +683,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
@ -706,6 +708,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -715,6 +718,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -731,7 +735,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));
@ -799,13 +803,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);

View File

@ -686,22 +686,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
@ -709,6 +711,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -718,6 +721,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -734,7 +738,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));
@ -802,13 +806,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);

View File

@ -682,22 +682,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
@ -705,6 +707,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -714,6 +717,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -730,7 +734,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));
@ -798,13 +802,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);

View File

@ -685,22 +685,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
@ -708,6 +710,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -717,6 +720,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -733,7 +737,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));
@ -801,13 +805,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);

View File

@ -682,22 +682,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
@ -705,6 +707,7 @@ x
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
select * from t1;
x
NULL
1
2
3
@ -714,6 +717,7 @@ x
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
x
NULL
1
2
3
@ -730,7 +734,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));
@ -798,13 +802,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);

View File

@ -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;

View File

@ -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;
#

View File

@ -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);

View File

@ -38,7 +38,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);

View File

@ -723,6 +723,17 @@ public:
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;
};
/****************************************************************************/
@ -2068,6 +2079,7 @@ public:
set_extraction_flag(*(int*)arg);
return 0;
}
virtual bool subselect_table_finder_processor(void *arg) { return 0; };
/*
TRUE if the expression depends only on the table indicated by tab_map

View File

@ -7078,3 +7078,27 @@ void Subq_materialization_tracker::report_partial_merge_keys(
for (uint i= 0; i < merge_keys_count; i++)
partial_match_array_sizes[i]= merge_keys[i]->get_key_buff_elements();
}
/*
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;
};

View File

@ -277,6 +277,7 @@ public:
{
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);

View File

@ -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"
@ -1122,7 +1123,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)
{
@ -1184,37 +1184,53 @@ retry:
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:
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())
{
DBUG_PRINT("info",
("convert merged to materialization to resolve the conflict"));
derived->change_refs_to_fields();
derived->set_materialized_derived();
goto retry;
}
}
DBUG_RETURN(res);
}
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))
{
if (param.dup == NULL)
return ERROR_TABLE;
return param.dup;
}
DBUG_ASSERT(param.dup == NULL);
}
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
@ -1233,6 +1249,25 @@ retry:
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;
@ -1264,12 +1299,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;
}

View File

@ -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,
@ -290,6 +289,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);

View File

@ -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
@ -714,6 +715,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();
@ -771,7 +774,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,
&unused_conds, FALSE)))
&unused_conds, FALSE, &cache_insert_values)))
{
retval= thd->is_error();
if (res < 0)
@ -1000,8 +1003,42 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
restore_record(table,s->default_values); // Get empty record
thd->reconsider_logging_format_for_iodup(table);
}
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))
{
@ -1009,7 +1046,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)++))
{
if (fields.elements || !value_count)
{
@ -1112,7 +1166,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
break;
thd->get_stmt_da()->inc_current_row_for_warning();
}
its.rewind();
itr->rewind();
iteration++;
} while (bulk_parameters_iterations(thd));
@ -1601,6 +1655,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:
@ -1622,7 +1677,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic, 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;
@ -1712,11 +1767,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)
{
@ -1725,10 +1781,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
@ -3857,6 +3933,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");
/*
@ -3867,7 +3944,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,
&select_lex->where, TRUE)))
&select_lex->where, TRUE, &cache_insert_values)))
DBUG_RETURN(res);
/*
@ -4050,8 +4127,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;

View File

@ -27,7 +27,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List_item *values,
List<Item> &update_fields,
List<Item> &update_values, enum_duplicates duplic,
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,

View File

@ -12047,3 +12047,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;
}

View File

@ -1666,6 +1666,10 @@ public:
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;

View File

@ -1287,6 +1287,7 @@ static bool mysql_test_insert(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");
/*
@ -1330,7 +1331,8 @@ static bool mysql_test_insert(Prepared_statement *stmt,
}
if (mysql_prepare_insert(thd, table_list, fields, values, update_fields,
update_values, duplic, &unused_conds, FALSE))
update_values, duplic, &unused_conds, FALSE,
&cache_results))
goto error;
value_count= values->elements;

View File

@ -3023,6 +3023,8 @@ private:
ulong m_table_ref_version;
};
#define ERROR_TABLE ((TABLE_LIST*) 0x1)
class Item;
/*

View File

@ -22626,6 +22626,164 @@ static void test_mdev_34958()
rc= mysql_query(mysql, "DROP TABLE t1, t2");
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
/*
@ -22980,6 +23138,7 @@ static struct my_tests_st my_tests[]= {
{ "test_mdev_34718_bd", test_mdev_34718_bd },
{ "test_mdev_34718_ad", test_mdev_34718_ad },
{ "test_mdev_34958", test_mdev_34958 },
{ "test_mdev_32086", test_mdev_32086 },
#endif
{ 0, 0 }
};