Commit 7eff2080 authored by Aleksey Midenkov's avatar Aleksey Midenkov

MDEV-14687 DELETE HISTORY in prepared stmt crash [fixes #421]

Also fixes broken truncate after 617e108f
parent c5d0c38e
...@@ -28,15 +28,23 @@ select * from t for system_time all; ...@@ -28,15 +28,23 @@ select * from t for system_time all;
a a
11 11
22 22
1
2 2
delete history from t before system_time timestamp now(6); prepare stmt from 'delete history from t before system_time timestamp now(6)';
execute stmt;
drop prepare stmt;
select * from t for system_time all; select * from t for system_time all;
a a
11 11
22 22
1 delete from t;
2 create or replace procedure truncate_sp()
begin
delete history from t before system_time timestamp now(6);
end~~
call truncate_sp;
select * from t for system_time all;
a
drop procedure truncate_sp;
### Issue #399, truncate partitioned table is now unimplemented ### Issue #399, truncate partitioned table is now unimplemented
create or replace table t (a int) create or replace table t (a int)
with system versioning with system versioning
...@@ -50,12 +58,14 @@ create or replace table t (i int) with system versioning; ...@@ -50,12 +58,14 @@ create or replace table t (i int) with system versioning;
delete history from t before system_time now(); delete history from t before system_time now();
create or replace view v as select * from t; create or replace view v as select * from t;
delete history from v before system_time now(); delete history from v before system_time now();
ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs ERROR HY000: DELETE HISTORY from VIEW is prohibited
create or replace table t (i int); create or replace table t (i int);
delete history from t before system_time now(); delete history from t before system_time now();
ERROR HY000: Table `t` is not system-versioned ERROR HY000: Table `t` is not system-versioned
create or replace view v as select * from t; create or replace view v as select * from t;
delete history from v before system_time now(); delete history from v before system_time now();
ERROR HY000: TRUNCATE table_name TO doesn't work with VIEWs ERROR HY000: DELETE HISTORY from VIEW is prohibited
prepare stmt from 'delete history from t before system_time now()';
ERROR HY000: Table `t` is not system-versioned
drop table t; drop table t;
drop view v; drop view v;
...@@ -25,8 +25,21 @@ update t set a=22 where a=2; ...@@ -25,8 +25,21 @@ update t set a=22 where a=2;
select * from t for system_time all; select * from t for system_time all;
delete history from t before system_time timestamp @ts1; delete history from t before system_time timestamp @ts1;
select * from t for system_time all; select * from t for system_time all;
delete history from t before system_time timestamp now(6); prepare stmt from 'delete history from t before system_time timestamp now(6)';
execute stmt; drop prepare stmt;
select * from t for system_time all; select * from t for system_time all;
delete from t;
delimiter ~~;
create or replace procedure truncate_sp()
begin
delete history from t before system_time timestamp now(6);
end~~
delimiter ;~~
call truncate_sp;
select * from t for system_time all;
drop procedure truncate_sp;
--echo ### Issue #399, truncate partitioned table is now unimplemented --echo ### Issue #399, truncate partitioned table is now unimplemented
...@@ -43,15 +56,17 @@ delete history from t before system_time current_timestamp; ...@@ -43,15 +56,17 @@ delete history from t before system_time current_timestamp;
create or replace table t (i int) with system versioning; create or replace table t (i int) with system versioning;
delete history from t before system_time now(); delete history from t before system_time now();
create or replace view v as select * from t; create or replace view v as select * from t;
--error ER_VERS_TRUNCATE_TO_VIEW --error ER_VERS_TRUNCATE_VIEW
delete history from v before system_time now(); delete history from v before system_time now();
create or replace table t (i int); create or replace table t (i int);
--error ER_VERS_NOT_VERSIONED --error ER_VERS_NOT_VERSIONED
delete history from t before system_time now(); delete history from t before system_time now();
create or replace view v as select * from t; create or replace view v as select * from t;
--error ER_VERS_TRUNCATE_TO_VIEW --error ER_VERS_TRUNCATE_VIEW
delete history from v before system_time now(); delete history from v before system_time now();
--error ER_VERS_NOT_VERSIONED
prepare stmt from 'delete history from t before system_time now()';
drop table t; drop table t;
drop view v; drop view v;
...@@ -7930,5 +7930,5 @@ ER_VERS_ALREADY_VERSIONED ...@@ -7930,5 +7930,5 @@ ER_VERS_ALREADY_VERSIONED
WARN_VERS_TRT_EXPERIMENTAL WARN_VERS_TRT_EXPERIMENTAL
eng "Transaction-based system versioning is EXPERIMENTAL and is subject to change in future." eng "Transaction-based system versioning is EXPERIMENTAL and is subject to change in future."
ER_VERS_TRUNCATE_TO_VIEW ER_VERS_TRUNCATE_VIEW
eng "TRUNCATE table_name TO doesn't work with VIEWs" eng "DELETE HISTORY from VIEW is prohibited"
...@@ -223,25 +223,21 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, ...@@ -223,25 +223,21 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel, static bool record_should_be_deleted(THD *thd, TABLE *table, SQL_SELECT *sel,
Explain_delete *explain) Explain_delete *explain, bool truncate_history)
{ {
bool check_delete= true;
if (table->versioned()) if (table->versioned())
{ {
bool row_is_alive= table->vers_end_field()->is_max(); bool historical= !table->vers_end_field()->is_max();
/* If we are doing TRUNCATE TABLE with SYSTEM_TIME condition then historical check_delete= truncate_history ? historical : !historical;
record is deleted and current record is kept. Otherwise alive record is
deleted and historical record is kept. */
if ((thd->lex->sql_command == SQLCOM_TRUNCATE && table->pos_in_table_list->vers_conditions)
? row_is_alive
: !row_is_alive)
return false;
} }
explain->tracker.on_record_read(); explain->tracker.on_record_read();
thd->inc_examined_row_count(1); thd->inc_examined_row_count(1);
if (table->vfield) if (table->vfield)
(void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE); (void) table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_DELETE);
if (!sel || sel->skip_record(thd) > 0) if (check_delete && (!sel || sel->skip_record(thd) > 0))
{ {
explain->tracker.on_record_after_where(); explain->tracker.on_record_after_where();
return true; return true;
...@@ -314,7 +310,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -314,7 +310,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
if (table_list->is_view_or_derived()) if (table_list->is_view_or_derived())
{ {
my_error(ER_VERS_TRUNCATE_TO_VIEW, MYF(0)); my_error(ER_VERS_TRUNCATE_VIEW, MYF(0));
DBUG_RETURN(true); DBUG_RETURN(true);
} }
...@@ -329,7 +325,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -329,7 +325,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
} }
#endif #endif
DBUG_ASSERT(!conds); DBUG_ASSERT(!conds || thd->stmt_arena->is_stmt_execute());
if (select_lex->vers_setup_conds(thd, table_list, &conds)) if (select_lex->vers_setup_conds(thd, table_list, &conds))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -708,7 +704,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -708,7 +704,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record()) && !thd->killed && while (!(error=info.read_record()) && !thd->killed &&
! thd->is_error()) ! thd->is_error())
{ {
if (record_should_be_deleted(thd, table, select, explain)) if (record_should_be_deleted(thd, table, select, explain, truncate_history))
{ {
table->file->position(table->record[0]); table->file->position(table->record[0]);
if ((error= deltempfile->unique_add((char*) table->file->ref))) if ((error= deltempfile->unique_add((char*) table->file->ref)))
...@@ -735,7 +731,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -735,7 +731,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
! thd->is_error()) ! thd->is_error())
{ {
if (delete_while_scanning) if (delete_while_scanning)
delete_record= record_should_be_deleted(thd, table, select, explain); delete_record= record_should_be_deleted(thd, table, select, explain,
truncate_history);
if (delete_record) if (delete_record)
{ {
if (!truncate_history && table->triggers && if (!truncate_history && table->triggers &&
...@@ -945,6 +942,11 @@ l ...@@ -945,6 +942,11 @@ l
select_lex->leaf_tables, FALSE, select_lex->leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE)) DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (table_list->vers_conditions &&
select_lex->vers_setup_conds(thd, table_list, conds))
{
DBUG_RETURN(TRUE);
}
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) || if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
setup_fields(thd, Ref_ptr_array(), setup_fields(thd, Ref_ptr_array(),
field_list, MARK_COLUMNS_READ, NULL, NULL, 0) || field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||
......
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