1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-40821 Wrong result after DELETE HISTORY or PORTION OF (10.11)

The parser assigned versioning conditions of DELETE HISTORY ... BEFORE
SYSTEM_TIME and period conditions of DELETE ... FOR PORTION OF to the
table pointed by last_table(). When the BEFORE SYSTEM_TIME or FOR
PORTION OF expression references another table (e.g. via a subquery or
a sequence function), last_table() is already switched to that table,
and the DELETE target gets no conditions.

DELETE HISTORY then deletes current rows permanently instead of
history, keeps the history it had to purge, and is checked for DELETE
privilege instead of DELETE HISTORY. DELETE HISTORY from a
non-versioned table is not rejected with ER_VERS_NOT_VERSIONED.
DELETE ... FOR PORTION OF deletes all rows of the table, ignoring the
period.

The fix assigns the conditions to the TABLE_LIST returned by
delete_single_table, i.e. the DELETE target itself, regardless of
tables added later in the statement.

DBUG_ASSERT in TABLE::vers_switch_partition() is removed. It checked
delete_history on last_table() and assumed no other table is opened
for write by DELETE HISTORY, which is false for the underlying table
of a view or a table locked by SELECT ... FOR UPDATE in the history
point. The DELETE HISTORY target is already skipped there by its own
delete_history check.
This commit is contained in:
Aleksey Midenkov
2026-09-21 19:23:26 +03:00
parent 2a96bc4385
commit e1eaa76df2
8 changed files with 260 additions and 10 deletions

View File

@@ -421,3 +421,20 @@ 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

View File

@@ -268,3 +268,20 @@ 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

View File

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

View File

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

View File

@@ -372,6 +372,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

View File

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

View File

@@ -1873,8 +1873,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)

View File

@@ -1693,6 +1693,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> date_time_type;
%type <interval> interval
@@ -14010,7 +14011,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)))
@@ -14038,12 +14039,12 @@ delete_single_table:
Lex->query_tables= 0;
Lex->query_tables_last= &Lex->query_tables;
if (unlikely(!Select->
add_table_to_list(thd, $2, $3, TL_OPTION_UPDATING,
YYPS->m_lock_type,
YYPS->m_mdl_type,
Select->pop_index_hints(),
$5)))
if (!($$= Select->
add_table_to_list(thd, $2, $3, TL_OPTION_UPDATING,
YYPS->m_lock_type,
YYPS->m_mdl_type,
Select->pop_index_hints(),
$5)))
MYSQL_YYABORT;
Lex->auxiliary_table_list.first->correspondent_table=
Lex->query_tables;
@@ -14056,7 +14057,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;
}
;