diff --git a/mysql-test/suite/period/r/delete.result b/mysql-test/suite/period/r/delete.result index 2b0a97e03d8e1..65a28f97fab49 100644 --- a/mysql-test/suite/period/r/delete.result +++ b/mysql-test/suite/period/r/delete.result @@ -421,3 +421,33 @@ id s e drop table t1; drop table log_tbl; drop procedure log; +# +# MDEV-40821 SIGSEGV in Window_funcs_sort::setup +# +# Bound referencing another table must not delete whole rows +create table t1 (x int, s date, e date, period for app(s,e)); +create table t2 (d date); +insert into t1 values (1, '2000-01-01', '2000-01-10'), +(2, '2000-02-01', '2000-02-10'); +insert into t2 values ('2000-01-05'); +delete from t1 for portion of app from (select d from t2) to '2000-01-20'; +ERROR HY000: Expression in FOR PORTION OF must be constant +select * from t1; +x s e +1 2000-01-01 2000-01-10 +2 2000-02-01 2000-02-10 +drop table t1, t2; +# End of 10.11 tests +# +# MDEV-40821 SIGSEGV in Window_funcs_sort::setup +# +# Subquery on the target: row must be split, not deleted +create table t1 (id int, s date, e date, period for app(s,e)); +insert into t1 values (1, '2000-01-01', '2000-01-10'); +delete from t1 for portion of app from '2000-01-05' to '2000-01-20' + where id in (select id from t1); +select * from t1; +id s e +1 2000-01-01 2000-01-05 +drop table t1; +# End of 11.4 tests diff --git a/mysql-test/suite/period/t/delete.test b/mysql-test/suite/period/t/delete.test index 676fa256f95ed..ae28e9f7527bd 100644 --- a/mysql-test/suite/period/t/delete.test +++ b/mysql-test/suite/period/t/delete.test @@ -268,3 +268,33 @@ select * from t1; drop table t1; drop table log_tbl; drop procedure log; + +--echo # +--echo # MDEV-40821 SIGSEGV in Window_funcs_sort::setup +--echo # +--echo # Bound referencing another table must not delete whole rows +create table t1 (x int, s date, e date, period for app(s,e)); +create table t2 (d date); +insert into t1 values (1, '2000-01-01', '2000-01-10'), + (2, '2000-02-01', '2000-02-10'); +insert into t2 values ('2000-01-05'); +--error ER_NOT_CONSTANT_EXPRESSION +delete from t1 for portion of app from (select d from t2) to '2000-01-20'; +--sorted_result +select * from t1; +drop table t1, t2; + +--echo # End of 10.11 tests + +--echo # +--echo # MDEV-40821 SIGSEGV in Window_funcs_sort::setup +--echo # +--echo # Subquery on the target: row must be split, not deleted +create table t1 (id int, s date, e date, period for app(s,e)); +insert into t1 values (1, '2000-01-01', '2000-01-10'); +delete from t1 for portion of app from '2000-01-05' to '2000-01-20' + where id in (select id from t1); +select * from t1; +drop table t1; + +--echo # End of 11.4 tests diff --git a/mysql-test/suite/versioning/r/delete_history.result b/mysql-test/suite/versioning/r/delete_history.result index e0ba80e24363b..adff2933a9987 100644 --- a/mysql-test/suite/versioning/r/delete_history.result +++ b/mysql-test/suite/versioning/r/delete_history.result @@ -504,4 +504,101 @@ create table t (a int) with system versioning; insert into t values (1),(2); prepare stmt from 'select * from t for system_time as of timestamp ?'; drop table t; +# +# MDEV-40821 SIGSEGV in Window_funcs_sort::setup +# +# Point referencing another table must purge only history +create table t1 (x int) with system versioning; +create table t2 (d timestamp(6)); +set timestamp= unix_timestamp('2000-01-01 00:00:01'); +insert into t1 values (1), (2); +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +delete from t1 where x = 2; +insert into t2 values ('2000-01-01 00:00:03'); +set timestamp= default; +delete history from t1 before system_time (select d from t2); +select * from t1; +x +1 +select * from t1 for system_time all; +x +1 +# Prepared statement +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (3); +delete from t1 where x = 3; +set timestamp= default; +prepare stmt from 'delete history from t1 before system_time (select d from t2)'; +execute stmt; +select * from t1 for system_time all; +x +1 +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (4); +delete from t1 where x = 4; +set timestamp= default; +execute stmt; +select * from t1 for system_time all; +x +1 +drop prepare stmt; +# Sequence function in the point +create sequence s start with 3 engine=myisam; +select nextval(s); +nextval(s) +3 +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (5); +delete from t1 where x = 5; +set timestamp= default; +delete history from t1 before system_time +timestampadd(second, lastval(s), '2000-01-01 00:00:00'); +select * from t1 for system_time all; +x +1 +drop sequence s; +# Non-versioned table must be rejected +create table t3 (x int); +insert into t3 values (1); +delete history from t3 before system_time (select d from t2); +ERROR HY000: Table `t3` is not system-versioned +select * from t3; +x +1 +drop table t3; +# View over partitioned table +create table t3 (x int) with system versioning +partition by system_time limit 1; +create view v as select * from t3; +delete history from v; +ERROR 42S02: 'v' is a view +drop view v; +drop table t3; +# Locking subquery on partitioned table +create table t3 (d timestamp(6)) with system versioning +partition by system_time limit 1; +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (6); +delete from t1 where x = 6; +insert into t3 values ('2000-01-01 00:00:03'); +set timestamp= default; +delete history from t1 before system_time (select d from t3 for update); +select * from t1 for system_time all; +x +1 +# Subquery with its own FOR SYSTEM_TIME +create table t4 (d timestamp(6)) with system versioning; +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (7); +delete from t1 where x = 7; +insert into t4 values ('2000-01-01 00:00:03'); +set timestamp= unix_timestamp('2000-01-01 00:00:03'); +update t4 set d= '2000-01-01 00:00:00'; +set timestamp= default; +delete history from t1 before system_time +(select max(d) from t4 for system_time all); +select * from t1 for system_time all; +x +1 +drop table t1, t2, t3, t4; # End of 10.11 tests diff --git a/mysql-test/suite/versioning/r/not_embedded.result b/mysql-test/suite/versioning/r/not_embedded.result index 5d8380e096962..eb03338fb115c 100644 --- a/mysql-test/suite/versioning/r/not_embedded.result +++ b/mysql-test/suite/versioning/r/not_embedded.result @@ -93,3 +93,21 @@ connection default; commit; drop table t; set timestamp= default; +# +# MDEV-40821 SIGSEGV in Window_funcs_sort::setup +# +# DELETE privilege is not enough for DELETE HISTORY with a subquery +create database mysqltest; +create table mysqltest.t (a int) with system versioning; +create table mysqltest.t2 (d timestamp(6)); +insert into mysqltest.t2 values (now(6)); +create user mysqltest_1@localhost; +grant select, delete on mysqltest.* to mysqltest_1@localhost; +connect user1,localhost,mysqltest_1,,mysqltest; +delete history from t before system_time (select d from t2); +ERROR 42000: DELETE HISTORY command denied to user 'mysqltest_1'@'localhost' for table `mysqltest`.`t` +disconnect user1; +connection default; +drop user mysqltest_1@localhost; +drop database mysqltest; +# End of 10.11 tests diff --git a/mysql-test/suite/versioning/t/delete_history.test b/mysql-test/suite/versioning/t/delete_history.test index 65f1e8f22245b..d1483132be931 100644 --- a/mysql-test/suite/versioning/t/delete_history.test +++ b/mysql-test/suite/versioning/t/delete_history.test @@ -371,6 +371,88 @@ insert into t values (1),(2); prepare stmt from 'select * from t for system_time as of timestamp ?'; drop table t; +--echo # +--echo # MDEV-40821 SIGSEGV in Window_funcs_sort::setup +--echo # +--echo # Point referencing another table must purge only history +create table t1 (x int) with system versioning; +create table t2 (d timestamp(6)); +set timestamp= unix_timestamp('2000-01-01 00:00:01'); +insert into t1 values (1), (2); +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +delete from t1 where x = 2; +insert into t2 values ('2000-01-01 00:00:03'); +set timestamp= default; +delete history from t1 before system_time (select d from t2); +select * from t1; +select * from t1 for system_time all; +--echo # Prepared statement +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (3); +delete from t1 where x = 3; +set timestamp= default; +prepare stmt from 'delete history from t1 before system_time (select d from t2)'; +execute stmt; +select * from t1 for system_time all; +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (4); +delete from t1 where x = 4; +set timestamp= default; +execute stmt; +select * from t1 for system_time all; +drop prepare stmt; +--echo # Sequence function in the point +create sequence s start with 3 engine=myisam; +--disable_ps2_protocol +select nextval(s); +--enable_ps2_protocol +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (5); +delete from t1 where x = 5; +set timestamp= default; +delete history from t1 before system_time + timestampadd(second, lastval(s), '2000-01-01 00:00:00'); +select * from t1 for system_time all; +drop sequence s; +--echo # Non-versioned table must be rejected +create table t3 (x int); +insert into t3 values (1); +--error ER_VERS_NOT_VERSIONED +delete history from t3 before system_time (select d from t2); +select * from t3; +drop table t3; +--echo # View over partitioned table +create table t3 (x int) with system versioning + partition by system_time limit 1; +create view v as select * from t3; +--error ER_IT_IS_A_VIEW +delete history from v; +drop view v; +drop table t3; +--echo # Locking subquery on partitioned table +create table t3 (d timestamp(6)) with system versioning + partition by system_time limit 1; +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (6); +delete from t1 where x = 6; +insert into t3 values ('2000-01-01 00:00:03'); +set timestamp= default; +delete history from t1 before system_time (select d from t3 for update); +select * from t1 for system_time all; +--echo # Subquery with its own FOR SYSTEM_TIME +create table t4 (d timestamp(6)) with system versioning; +set timestamp= unix_timestamp('2000-01-01 00:00:02'); +insert into t1 values (7); +delete from t1 where x = 7; +insert into t4 values ('2000-01-01 00:00:03'); +set timestamp= unix_timestamp('2000-01-01 00:00:03'); +update t4 set d= '2000-01-01 00:00:00'; +set timestamp= default; +delete history from t1 before system_time + (select max(d) from t4 for system_time all); +select * from t1 for system_time all; +drop table t1, t2, t3, t4; + --echo # End of 10.11 tests --source suite/versioning/common_finish.inc diff --git a/mysql-test/suite/versioning/t/not_embedded.test b/mysql-test/suite/versioning/t/not_embedded.test index 38f42a44587c1..73953045146f4 100644 --- a/mysql-test/suite/versioning/t/not_embedded.test +++ b/mysql-test/suite/versioning/t/not_embedded.test @@ -105,3 +105,23 @@ reap; commit; drop table t; set timestamp= default; + +--echo # +--echo # MDEV-40821 SIGSEGV in Window_funcs_sort::setup +--echo # +--echo # DELETE privilege is not enough for DELETE HISTORY with a subquery +create database mysqltest; +create table mysqltest.t (a int) with system versioning; +create table mysqltest.t2 (d timestamp(6)); +insert into mysqltest.t2 values (now(6)); +create user mysqltest_1@localhost; +grant select, delete on mysqltest.* to mysqltest_1@localhost; +connect (user1,localhost,mysqltest_1,,mysqltest); +--error ER_TABLEACCESS_DENIED_ERROR +delete history from t before system_time (select d from t2); +disconnect user1; +connection default; +drop user mysqltest_1@localhost; +drop database mysqltest; + +--echo # End of 10.11 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index dee70e54d0368..8377d6c635b45 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1878,8 +1878,6 @@ bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list, } break; } - DBUG_ASSERT(!thd->lex->last_table() || - !thd->lex->last_table()->vers_conditions.delete_history); } if (table_list->partition_names) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index fed5b4c7f7ec8..9f059d8331290 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1606,7 +1606,8 @@ bool Sql_cmd_delete::processing_as_multitable_delete_prohibited(THD *thd) return ((select_lex->order_list.elements && select_lex->limit_params.select_limit) || - thd->lex->has_returning()); + thd->lex->has_returning() || + thd->lex->period_conditions.is_set()); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 38704d7909de9..d9d5dd554e608 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1675,6 +1675,7 @@ rule: derived_table_list table_reference_list_parens nested_table_reference_list join_table_parens update_table_list table_function + delete_single_table %type date_time_type; %type interval @@ -13669,7 +13670,7 @@ delete_part2: | HISTORY_SYM delete_single_table opt_delete_system_time { LEX *lex= Lex; - lex->last_table()->vers_conditions= lex->vers_conditions; + $2->vers_conditions= lex->vers_conditions; lex->sql_command= SQLCOM_DELETE; if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_delete(false))) @@ -13697,12 +13698,12 @@ delete_single_table: Lex->query_tables= 0; Lex->query_tables_last= &Lex->query_tables; - if (unlikely(!Select-> - add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, - YYPS->m_lock_type, - YYPS->m_mdl_type, - NULL, - $3))) + if (!($$= Select-> + add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, + $3))) MYSQL_YYABORT; Lex->auxiliary_table_list.first->correspondent_table= Lex->query_tables; @@ -13715,7 +13716,7 @@ delete_single_table_for_period: delete_single_table opt_for_portion_of_time_clause { if ($2) - Lex->last_table()->period_conditions= Lex->period_conditions; + $1->period_conditions= Lex->period_conditions; } ;