Commit c88ca2c2 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-8701 Crash on derived query

MDEV-8938 Server Crash on Update with joins

Make unique table check after setup_fields of update because unique table can materialize table and we do not need field resolving after materialization.
parent df804208
...@@ -618,3 +618,62 @@ Variable_name Value ...@@ -618,3 +618,62 @@ Variable_name Value
Handler_update 5 Handler_update 5
ROLLBACK; ROLLBACK;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# MDEV-8938: Server Crash on Update with joins
#
CREATE TABLE `t1` (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
UPDATE `t1` SET value = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `t1` WHERE `name`="consoleproxy.url.domain") AS `temptable` WHERE `temptable`.`name`="consoleproxy.url.domain")) WHERE `name`="consoleproxy.url.domain";
drop table t1;
CREATE TABLE `t1` (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
create table t2 (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
UPDATE t1
SET value = (SELECT value FROM t2 WHERE `name`= t1.name)
WHERE value is null ;
drop table t1,t2;
#
#MDEV-8701: Crash on derived query
#
CREATE TABLE t1 (
data_exit_entry_id int(11) NOT NULL,
data_entry_id int(11) NOT NULL,
data_entry_exit_id int(11) NOT NULL,
data_exit_entry_quantity double NOT NULL
) DEFAULT CHARSET=utf8;
CREATE TABLE t2 (
data_entry_id int(11) NOT NULL,
data_entry_cost double NOT NULL,
data_entry_quantity double NOT NULL
) DEFAULT CHARSET=utf8;
create algorithm=temptable view v1 as SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost
FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id;
UPDATE t2
SET data_entry_cost
= ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost)
FROM
v1 AS query
WHERE data_entry_exit_id = t2.data_entry_id
)
);
UPDATE t2
SET data_entry_cost
= ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost)
FROM
( SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost
FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id) AS query
WHERE data_entry_exit_id = t2.data_entry_id
)
);
drop view v1;
drop table t1, t2;
...@@ -559,3 +559,76 @@ SHOW STATUS LIKE 'HANDLER_UPDATE'; ...@@ -559,3 +559,76 @@ SHOW STATUS LIKE 'HANDLER_UPDATE';
ROLLBACK; ROLLBACK;
DROP TABLE t1, t2; DROP TABLE t1, t2;
--echo #
--echo # MDEV-8938: Server Crash on Update with joins
--echo #
CREATE TABLE `t1` (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
UPDATE `t1` SET value = CONCAT("*.",(SELECT `temptable`.`value` FROM (SELECT * FROM `t1` WHERE `name`="consoleproxy.url.domain") AS `temptable` WHERE `temptable`.`name`="consoleproxy.url.domain")) WHERE `name`="consoleproxy.url.domain";
drop table t1;
CREATE TABLE `t1` (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
create table t2 (
`name` varchar(255) NOT NULL,
`value` varchar(4095) DEFAULT NULL,
PRIMARY KEY (`name`)
);
UPDATE t1
SET value = (SELECT value FROM t2 WHERE `name`= t1.name)
WHERE value is null ;
drop table t1,t2;
--echo #
--echo #MDEV-8701: Crash on derived query
--echo #
CREATE TABLE t1 (
data_exit_entry_id int(11) NOT NULL,
data_entry_id int(11) NOT NULL,
data_entry_exit_id int(11) NOT NULL,
data_exit_entry_quantity double NOT NULL
) DEFAULT CHARSET=utf8;
CREATE TABLE t2 (
data_entry_id int(11) NOT NULL,
data_entry_cost double NOT NULL,
data_entry_quantity double NOT NULL
) DEFAULT CHARSET=utf8;
create algorithm=temptable view v1 as SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost
FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id;
UPDATE t2
SET data_entry_cost
= ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost)
FROM
v1 AS query
WHERE data_entry_exit_id = t2.data_entry_id
)
);
UPDATE t2
SET data_entry_cost
= ( ( SELECT SUM(data_exit_entry_quantity * data_entry_cost)
FROM
( SELECT data_entry_exit_id, data_exit_entry_quantity, data_entry_cost
FROM t1 INNER JOIN t2 as dt ON dt.data_entry_id = t1.data_entry_id) AS query
WHERE data_entry_exit_id = t2.data_entry_id
)
);
drop view v1;
drop table t1, t2;
...@@ -1408,7 +1408,8 @@ static int mysql_test_update(Prepared_statement *stmt, ...@@ -1408,7 +1408,8 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege); (SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL); table_list->register_want_access(SELECT_ACL);
#endif #endif
if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0)) if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
check_unique_table(thd, table_list))
goto error; goto error;
/* TODO: here we should send types of placeholders to the client. */ /* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0); DBUG_RETURN(0);
......
...@@ -367,6 +367,9 @@ int mysql_update(THD *thd, ...@@ -367,6 +367,9 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
} }
if (check_unique_table(thd, table_list))
DBUG_RETURN(TRUE);
/* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */
if (select_lex->optimize_unflattened_subqueries(false)) if (select_lex->optimize_unflattened_subqueries(false))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -1036,20 +1039,31 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, ...@@ -1036,20 +1039,31 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
setup_ftfuncs(select_lex)) setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* Check that we are not using table that we are updating in a sub select */ select_lex->fix_prepare_information(thd, conds, &fake_conds);
{ DBUG_RETURN(FALSE);
}
/**
Check that we are not using table that we are updating in a sub select
@param thd Thread handle
@param table_list List of table with first to check
@retval TRUE Error
@retval FALSE OK
*/
bool check_unique_table(THD *thd, TABLE_LIST *table_list)
{
TABLE_LIST *duplicate; TABLE_LIST *duplicate;
DBUG_ENTER("check_unique_table");
if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0))) if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{ {
update_non_unique_table_error(table_list, "UPDATE", duplicate); update_non_unique_table_error(table_list, "UPDATE", duplicate);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
}
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
/*************************************************************************** /***************************************************************************
Update multiple tables from join Update multiple tables from join
***************************************************************************/ ***************************************************************************/
......
...@@ -27,6 +27,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; ...@@ -27,6 +27,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT;
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order); Item **conds, uint order_num, ORDER *order);
bool check_unique_table(THD *thd, TABLE_LIST *table_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds, List<Item> &values,COND *conds,
uint order_num, ORDER *order, ha_rows limit, uint order_num, ORDER *order, ha_rows limit,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment