Skip to content

Commit

Permalink
0.6: truncate history feature [closes #96]
Browse files Browse the repository at this point in the history
  • Loading branch information
kevgs authored and midenok committed May 5, 2017
1 parent 4c37011 commit c9e4ac4
Show file tree
Hide file tree
Showing 15 changed files with 301 additions and 29 deletions.
115 changes: 115 additions & 0 deletions mysql-test/suite/versioning/r/truncate_history.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
create table t (a int);
truncate t for system_time all;
ERROR HY000: System Versioning required: `FOR SYSTEM_TIME` query
create procedure truncate_history_of_t()
begin
prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)';
execute stmt;
drop prepare stmt;
end~~
create or replace table t (a int) with system versioning;
insert into t values (1);
update t set a=2;
select * from t for system_time all;
a
2
1
set @test = 'correct';
create trigger trg_before before delete on t for each row set @test = 'incorrect';
create trigger trg_after after delete on t for each row set @test = 'incorrect';
truncate t for system_time all;
select * from t for system_time all;
a
2
select @test from t;
@test
correct
drop trigger trg_before;
drop trigger trg_after;
update t set a=3;
update t set a=4;
truncate t for system_time as of timestamp now(6);
select * from t for system_time all;
a
4
2
3
truncate t for system_time timestamp between '1-1-1' and now(6);
select * from t for system_time all;
a
4
update t set a=5;
truncate t for system_time timestamp from '1-1-1' to now(6);
select * from t for system_time all;
a
5
update t set a=6;
call truncate_history_of_t();
select * from t for system_time all;
a
6
set @ts1 = now(6);
update t set a=7;
set @ts2 = now(6);
update t set a=8;
truncate t for system_time timestamp from '1-1-1' to @ts1;
select * from t for system_time all;
a
8
7
update t set a=9;
truncate t for system_time timestamp between '1-1-1' and @ts2;
select * from t for system_time all;
a
9
8
create or replace table t (a int) with system versioning engine=innodb;
insert into t values (1);
update t set a=2;
select * from t for system_time all;
a
2
1
truncate t for system_time all;
select * from t for system_time all;
a
2
update t set a=3;
update t set a=4;
truncate t for system_time as of timestamp now(6);
select * from t for system_time all;
a
4
2
3
truncate t for system_time timestamp between '1-1-1' and now(6);
select * from t for system_time all;
a
4
update t set a=5;
truncate t for system_time timestamp from '1-1-1' to now(6);
select * from t for system_time all;
a
5
update t set a=6;
call truncate_history_of_t();
select * from t for system_time all;
a
6
set @ts1 = now(6);
update t set a=7;
set @ts2 = now(6);
update t set a=8;
truncate t for system_time timestamp from '1-1-1' to @ts1;
select * from t for system_time all;
a
8
7
update t set a=9;
truncate t for system_time timestamp between '1-1-1' and @ts2;
select * from t for system_time all;
a
9
8
drop table t;
drop procedure truncate_history_of_t;
7 changes: 7 additions & 0 deletions mysql-test/suite/versioning/r/truncate_innodb_rpl.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
include/master-slave.inc
[connection master]
create table t (a int) with system versioning engine=innodb;
truncate t for system_time all;
ERROR HY000: `TRUNCATE FOR SYSTEM_TIME with row-based replication` is not allowed for versioned table
drop table t;
include/rpl_end.inc
94 changes: 94 additions & 0 deletions mysql-test/suite/versioning/t/truncate_history.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
-- source include/have_innodb.inc

create table t (a int);
--error ER_VERSIONING_REQUIRED
truncate t for system_time all;

delimiter ~~;
create procedure truncate_history_of_t()
begin
prepare stmt from 'truncate t for system_time timestamp between \'1-1-1\' and now(6)';
execute stmt;
drop prepare stmt;
end~~
delimiter ;~~

create or replace table t (a int) with system versioning;
insert into t values (1);
update t set a=2;
select * from t for system_time all;

set @test = 'correct';
create trigger trg_before before delete on t for each row set @test = 'incorrect';
create trigger trg_after after delete on t for each row set @test = 'incorrect';

truncate t for system_time all;
select * from t for system_time all;

select @test from t;
drop trigger trg_before;
drop trigger trg_after;

update t set a=3;
update t set a=4;
truncate t for system_time as of timestamp now(6);
select * from t for system_time all;

truncate t for system_time timestamp between '1-1-1' and now(6);
select * from t for system_time all;

update t set a=5;
truncate t for system_time timestamp from '1-1-1' to now(6);
select * from t for system_time all;

update t set a=6;
call truncate_history_of_t();
select * from t for system_time all;

set @ts1 = now(6);
update t set a=7;
set @ts2 = now(6);
update t set a=8;
truncate t for system_time timestamp from '1-1-1' to @ts1;
select * from t for system_time all;
update t set a=9;
truncate t for system_time timestamp between '1-1-1' and @ts2;
select * from t for system_time all;


create or replace table t (a int) with system versioning engine=innodb;
insert into t values (1);
update t set a=2;
select * from t for system_time all;

truncate t for system_time all;
select * from t for system_time all;

update t set a=3;
update t set a=4;
truncate t for system_time as of timestamp now(6);
select * from t for system_time all;

truncate t for system_time timestamp between '1-1-1' and now(6);
select * from t for system_time all;

update t set a=5;
truncate t for system_time timestamp from '1-1-1' to now(6);
select * from t for system_time all;

update t set a=6;
call truncate_history_of_t();
select * from t for system_time all;

set @ts1 = now(6);
update t set a=7;
set @ts2 = now(6);
update t set a=8;
truncate t for system_time timestamp from '1-1-1' to @ts1;
select * from t for system_time all;
update t set a=9;
truncate t for system_time timestamp between '1-1-1' and @ts2;
select * from t for system_time all;

drop table t;
drop procedure truncate_history_of_t;
10 changes: 10 additions & 0 deletions mysql-test/suite/versioning/t/truncate_innodb_rpl.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- source include/have_binlog_format_row.inc
-- source include/master-slave.inc
-- source include/have_innodb.inc

create table t (a int) with system versioning engine=innodb;
--error ER_VERS_NOT_ALLOWED
truncate t for system_time all;
drop table t;

-- source include/rpl_end.inc
2 changes: 1 addition & 1 deletion sql/handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5659,7 +5659,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
1 Row needs to be logged
*/

inline bool handler::check_table_binlog_row_based(bool binlog_row)
bool handler::check_table_binlog_row_based(bool binlog_row)
{
if (unlikely((table->in_use->variables.sql_log_bin_off)))
return 0; /* Called by partitioning engine */
Expand Down
2 changes: 1 addition & 1 deletion sql/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4079,7 +4079,7 @@ class handler :public Sql_alloc
virtual int delete_table(const char *name);

public:
inline bool check_table_binlog_row_based(bool binlog_row);
bool check_table_binlog_row_based(bool binlog_row);
private:
/* Cache result to avoid extra calls */
inline void mark_trx_read_write()
Expand Down
3 changes: 3 additions & 0 deletions sql/share/errmsg-utf8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7522,3 +7522,6 @@ WARN_VERS_PARAMETERS

WARN_VERS_PART_ROTATION
eng "Switching from partition %`s to %`s"

ER_VERS_NOT_ALLOWED
eng "%`s is not allowed for versioned table"
58 changes: 42 additions & 16 deletions sql/sql_delete.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,13 @@ void Update_plan::save_explain_data_intern(MEM_ROOT *mem_root,
inline
int TABLE::delete_row()
{
int error;
if (!versioned_by_sql())
error= file->ha_delete_row(record[0]);
else
{
store_record(this, record[1]);
Field *sys_trx_end= vers_end_field();
sys_trx_end->set_time();
error= file->ha_update_row(record[1], record[0]);
}
return error;
}
if (!versioned_by_sql() || !vers_end_field()->is_max())
return file->ha_delete_row(record[0]);

store_record(this, record[1]);
vers_end_field()->set_time();
return file->ha_update_row(record[1], record[0]);
}

/**
Implement DELETE SQL word.
Expand Down Expand Up @@ -269,6 +263,34 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (open_and_lock_tables(thd, table_list, TRUE, 0))
DBUG_RETURN(TRUE);

bool truncate_history=
select_lex->vers_conditions.type != FOR_SYSTEM_TIME_UNSPECIFIED;
if (truncate_history)
{
TABLE *table= table_list->table;
DBUG_ASSERT(table);

if (table->versioned_by_engine() &&
table->file->check_table_binlog_row_based(1))
{
my_error(ER_VERS_NOT_ALLOWED, MYF(0),
"TRUNCATE FOR SYSTEM_TIME with row-based replication");
DBUG_RETURN(TRUE);
}

DBUG_ASSERT(!conds);
if (vers_setup_select(thd, table_list, &conds, select_lex))
DBUG_RETURN(TRUE);

// trx_sees() in InnoDB reads sys_trx_start
if (!table->versioned_by_sql() &&
(select_lex->vers_conditions.type == FOR_SYSTEM_TIME_BETWEEN ||
select_lex->vers_conditions.type == FOR_SYSTEM_TIME_FROM_TO))
{
bitmap_set_bit(table->read_set, table->vers_start_field()->field_index);
}
}

if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT))
DBUG_RETURN(TRUE);
if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE))
Expand Down Expand Up @@ -577,9 +599,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
if (table->versioned() && !table->vers_end_field()->is_max())
if (table->versioned())
{
continue;
bool row_is_alive= table->vers_end_field()->is_max();
if (truncate_history && row_is_alive)
continue;
if (!truncate_history && !row_is_alive)
continue;
}

explain->tracker.on_record_read();
Expand All @@ -589,7 +615,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!select || select->skip_record(thd) > 0)
{
explain->tracker.on_record_after_where();
if (table->triggers &&
if (!truncate_history && table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE))
{
Expand All @@ -607,7 +633,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!error)
{
deleted++;
if (table->triggers &&
if (!truncate_history && table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, FALSE))
{
Expand Down
4 changes: 2 additions & 2 deletions sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,8 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
DBUG_RETURN(res);
}

static int
vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr, SELECT_LEX *slex)
int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
SELECT_LEX *slex)
{
DBUG_ENTER("vers_setup_select");
#define newx new (thd->mem_root)
Expand Down
3 changes: 3 additions & 0 deletions sql/sql_select.h
Original file line number Diff line number Diff line change
Expand Up @@ -2301,4 +2301,7 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort);
JOIN_TAB *first_explain_order_tab(JOIN* join);
JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab);

int vers_setup_select(THD *thd, TABLE_LIST *tables, COND **where_expr,
SELECT_LEX *slex);

#endif /* SQL_SELECT_INCLUDED */
9 changes: 7 additions & 2 deletions sql/sql_truncate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
#include "sql_truncate.h"
#include "wsrep_mysqld.h"
#include "sql_show.h" //append_identifier()

#include "sql_select.h"
#include "sql_delete.h"

/**
Append a list of field names to a string.
Expand Down Expand Up @@ -480,7 +481,6 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
DBUG_RETURN(error);
}


/**
Execute a TRUNCATE statement at runtime.
Expand All @@ -495,6 +495,11 @@ bool Sql_cmd_truncate_table::execute(THD *thd)
TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
DBUG_ENTER("Sql_cmd_truncate_table::execute");

bool truncate_history= thd->lex->current_select->vers_conditions.type !=
FOR_SYSTEM_TIME_UNSPECIFIED;
if (truncate_history)
DBUG_RETURN(mysql_delete(thd, first_table, NULL, NULL, -1, 0, NULL));

if (check_one_table_access(thd, DROP_ACL, first_table))
DBUG_RETURN(res);

Expand Down
Loading

0 comments on commit c9e4ac4

Please sign in to comment.