Skip to content

Commit 7eff208

Browse files
committed
MDEV-14687 DELETE HISTORY in prepared stmt crash [fixes #421]
Also fixes broken truncate after 617e108
1 parent c5d0c38 commit 7eff208

File tree

4 files changed

+52
-25
lines changed

4 files changed

+52
-25
lines changed

mysql-test/suite/versioning/r/truncate.result

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,23 @@ select * from t for system_time all;
2828
a
2929
11
3030
22
31-
1
3231
2
33-
delete history from t before system_time timestamp now(6);
32+
prepare stmt from 'delete history from t before system_time timestamp now(6)';
33+
execute stmt;
34+
drop prepare stmt;
3435
select * from t for system_time all;
3536
a
3637
11
3738
22
38-
1
39-
2
39+
delete from t;
40+
create or replace procedure truncate_sp()
41+
begin
42+
delete history from t before system_time timestamp now(6);
43+
end~~
44+
call truncate_sp;
45+
select * from t for system_time all;
46+
a
47+
drop procedure truncate_sp;
4048
### Issue #399, truncate partitioned table is now unimplemented
4149
create or replace table t (a int)
4250
with system versioning
@@ -50,12 +58,14 @@ create or replace table t (i int) with system versioning;
5058
delete history from t before system_time now();
5159
create or replace view v as select * from t;
5260
delete history from v before system_time now();
53-
ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs
61+
ERROR HY000: DELETE HISTORY from VIEW is prohibited
5462
create or replace table t (i int);
5563
delete history from t before system_time now();
5664
ERROR HY000: Table `t` is not system-versioned
5765
create or replace view v as select * from t;
5866
delete history from v before system_time now();
59-
ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs
67+
ERROR HY000: DELETE HISTORY from VIEW is prohibited
68+
prepare stmt from 'delete history from t before system_time now()';
69+
ERROR HY000: Table `t` is not system-versioned
6070
drop table t;
6171
drop view v;

mysql-test/suite/versioning/t/truncate.test

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,21 @@ update t set a=22 where a=2;
2525
select * from t for system_time all;
2626
delete history from t before system_time timestamp @ts1;
2727
select * from t for system_time all;
28-
delete history from t before system_time timestamp now(6);
28+
prepare stmt from 'delete history from t before system_time timestamp now(6)';
29+
execute stmt; drop prepare stmt;
2930
select * from t for system_time all;
31+
delete from t;
32+
33+
delimiter ~~;
34+
create or replace procedure truncate_sp()
35+
begin
36+
delete history from t before system_time timestamp now(6);
37+
end~~
38+
delimiter ;~~
39+
call truncate_sp;
40+
select * from t for system_time all;
41+
42+
drop procedure truncate_sp;
3043

3144
--echo ### Issue #399, truncate partitioned table is now unimplemented
3245

@@ -43,15 +56,17 @@ delete history from t before system_time current_timestamp;
4356
create or replace table t (i int) with system versioning;
4457
delete history from t before system_time now();
4558
create or replace view v as select * from t;
46-
--error ER_VERS_TRUNCATE_TO_VIEW
59+
--error ER_VERS_TRUNCATE_VIEW
4760
delete history from v before system_time now();
4861

4962
create or replace table t (i int);
5063
--error ER_VERS_NOT_VERSIONED
5164
delete history from t before system_time now();
5265
create or replace view v as select * from t;
53-
--error ER_VERS_TRUNCATE_TO_VIEW
66+
--error ER_VERS_TRUNCATE_VIEW
5467
delete history from v before system_time now();
68+
--error ER_VERS_NOT_VERSIONED
69+
prepare stmt from 'delete history from t before system_time now()';
5570

5671
drop table t;
5772
drop view v;

sql/share/errmsg-utf8.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7930,5 +7930,5 @@ ER_VERS_ALREADY_VERSIONED
79307930
WARN_VERS_TRT_EXPERIMENTAL
79317931
eng "Transaction-based system versioning is EXPERIMENTAL and is subject to change in future."
79327932

7933-
ER_VERS_TRUNCATE_TO_VIEW
7934-
eng "TRUNCATE table_name TO doesn't work with VIEWs"
7933+
ER_VERS_TRUNCATE_VIEW
7934+
eng "DELETE HISTORY from VIEW is prohibited"

sql/sql_delete.cc

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -223,25 +223,21 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
223223

224224

225225
static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
226-
Explain_delete *explain)
226+
Explain_delete *explain, bool truncate_history)
227227
{
228+
bool check_delete= true;
229+
228230
if (table->versioned())
229231
{
230-
bool row_is_alive= table->vers_end_field()->is_max();
231-
/* If we are doing TRUNCATE TABLE with SYSTEM_TIME condition then historical
232-
record is deleted and current record is kept. Otherwise alive record is
233-
deleted and historical record is kept. */
234-
if ((thd->lex->sql_command == SQLCOM_TRUNCATE && table->pos_in_table_list->vers_conditions)
235-
? row_is_alive
236-
: !row_is_alive)
237-
return false;
232+
bool historical= !table->vers_end_field()->is_max();
233+
check_delete= truncate_history ? historical : !historical;
238234
}
239235

240236
explain->tracker.on_record_read();
241237
thd->inc_examined_row_count(1);
242238
if (table->vfield)
243239
(void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE);
244-
if (!sel || sel->skip_record(thd) > 0)
240+
if (check_delete && (!sel || sel->skip_record(thd) > 0))
245241
{
246242
explain->tracker.on_record_after_where();
247243
return true;
@@ -314,7 +310,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
314310
{
315311
if (table_list->is_view_or_derived())
316312
{
317-
my_error(ER_VERS_TRUNCATE_TO_VIEW, MYF(0));
313+
my_error(ER_VERS_TRUNCATE_VIEW, MYF(0));
318314
DBUG_RETURN(true);
319315
}
320316

@@ -329,7 +325,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
329325
}
330326
#endif
331327

332-
DBUG_ASSERT(!conds);
328+
DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute());
333329
if (select_lex->vers_setup_conds(thd, table_list, &conds))
334330
DBUG_RETURN(TRUE);
335331

@@ -708,7 +704,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
708704
while (!(error=info.read_record()) && !thd->killed &&
709705
! thd->is_error())
710706
{
711-
if (record_should_be_deleted(thd, table, select, explain))
707+
if (record_should_be_deleted(thd, table, select, explain, truncate_history))
712708
{
713709
table->file->position(table->record[0]);
714710
if ((error= deltempfile->unique_add((char*) table->file->ref)))
@@ -735,7 +731,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
735731
! thd->is_error())
736732
{
737733
if (delete_while_scanning)
738-
delete_record= record_should_be_deleted(thd, table, select, explain);
734+
delete_record= record_should_be_deleted(thd, table, select, explain,
735+
truncate_history);
739736
if (delete_record)
740737
{
741738
if (!truncate_history && table->triggers &&
@@ -945,6 +942,11 @@ l
945942
select_lex->leaf_tables, FALSE,
946943
DELETE_ACL, SELECT_ACL, TRUE))
947944
DBUG_RETURN(TRUE);
945+
if (table_list->vers_conditions &&
946+
select_lex->vers_setup_conds(thd, table_list, conds))
947+
{
948+
DBUG_RETURN(TRUE);
949+
}
948950
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
949951
setup_fields(thd, Ref_ptr_array(),
950952
field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||

0 commit comments

Comments
 (0)