From ececc50252fadca21201ffc69a63916bc6165e0b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 11 May 2019 12:18:34 +0200 Subject: [PATCH] MDEV-15966 Behavior for TRUNCATE versioned table is not documented and not covered by tests * add error for truncation of versioned tables: `ER_TRUNCATE_ILLEGAL_VERS` * make a full table open with `tdc_aquire_share` instead of just `ha_table_exists` check test suites run: main, parts, versioning Closes #785 --- .../federated/federatedx_versioning.result | 12 +++-- .../federated/federatedx_versioning.test | 13 +++-- .../suite/versioning/r/partition.result | 8 ---- mysql-test/suite/versioning/r/truncate.result | 24 ++++++++++ mysql-test/suite/versioning/t/partition.test | 9 ---- mysql-test/suite/versioning/t/truncate.test | 28 +++++++++++ sql/share/errmsg-utf8.txt | 2 + sql/sql_truncate.cc | 47 ++++++++++--------- 8 files changed, 98 insertions(+), 45 deletions(-) diff --git a/mysql-test/suite/federated/federatedx_versioning.result b/mysql-test/suite/federated/federatedx_versioning.result index 7af5a5f3f0c..a6572973ab1 100644 --- a/mysql-test/suite/federated/federatedx_versioning.result +++ b/mysql-test/suite/federated/federatedx_versioning.result @@ -46,8 +46,12 @@ x check_row(row_start, row_end) 4 HISTORICAL ROW select * from tf; x -# TRUNCATE +# MDEV-15966: Behavior for TRUNCATE versioned table is not documented +# and not covered by tests +# As of standard, TRUNCATE on versioned tables is forbidden truncate tf; +ERROR HY000: Got error 10000 'Error on remote system: 4160: Cannot truncate a versioned table' from FEDERATED +delete history from t1; select * from t1 for system_time all; x # REPLACE @@ -81,8 +85,10 @@ x check_row(row_start, row_end) 3 HISTORICAL ROW 4 HISTORICAL ROW # multi-UPDATE -truncate t1; -truncate t2; +delete from t1; +delete history from t1; +delete from t2; +delete history from t2; insert into t1 values (1); insert into t2 values (2, 2); update tf, t2f set tf.x= 11, t2f.y= 22; diff --git a/mysql-test/suite/federated/federatedx_versioning.test b/mysql-test/suite/federated/federatedx_versioning.test index 692edb5b00a..6d127f006e1 100644 --- a/mysql-test/suite/federated/federatedx_versioning.test +++ b/mysql-test/suite/federated/federatedx_versioning.test @@ -32,8 +32,13 @@ select *, check_row(row_start, row_end) from t1 for system_time all order by x; select * from tf; ---echo # TRUNCATE +--echo # MDEV-15966: Behavior for TRUNCATE versioned table is not documented +--echo # and not covered by tests +--echo # As of standard, TRUNCATE on versioned tables is forbidden +--error ER_GET_ERRMSG truncate tf; + +delete history from t1; select * from t1 for system_time all; --echo # REPLACE @@ -62,8 +67,10 @@ select *, check_row(row_start, row_end) from t1 for system_time all order by x; --echo # multi-UPDATE -truncate t1; -truncate t2; +delete from t1; +delete history from t1; +delete from t2; +delete history from t2; insert into t1 values (1); insert into t2 values (2, 2); update tf, t2f set tf.x= 11, t2f.y= 22; diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 9b6f2201c22..cf6f188372c 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -396,14 +396,6 @@ for each row select count(*) from t1 into @a; Warnings: Warning 1287 ' INTO FROM...' instead insert into t2 values (1); -# MDEV-14741 Assertion `(trx)->start_file == 0' failed in row_truncate_table_for_mysql() -create or replace table t1 (i int) with system versioning -partition by system_time interval 1 hour ( -partition p1 history, -partition pn current); -set autocommit= off; -truncate table t1; -set autocommit= on; # MDEV-14747 ALTER PARTITION BY SYSTEM_TIME after LOCK TABLES create or replace table t1 (x int) with system versioning; lock table t1 write; diff --git a/mysql-test/suite/versioning/r/truncate.result b/mysql-test/suite/versioning/r/truncate.result index d38b9eed162..706883bb04b 100644 --- a/mysql-test/suite/versioning/r/truncate.result +++ b/mysql-test/suite/versioning/r/truncate.result @@ -106,5 +106,29 @@ call pr; call pr; drop procedure pr; drop table t1; +# MDEV-15966 Behavior for TRUNCATE versioned table is not documented and not covered by tests +create or replace table t1 (id int); +create or replace table t2 (id int) with system versioning; +# force cleaning table shares +flush tables t1, t2; +truncate table t1; +truncate table t2; +ERROR HY000: Cannot truncate a versioned table +# fetch table shares +describe t1; +Field Type Null Key Default Extra +id int(11) YES NULL +describe t2; +Field Type Null Key Default Extra +id int(11) YES NULL +truncate table t1; +truncate table t2; +ERROR HY000: Cannot truncate a versioned table +# enter locked tables mode +lock tables t1 WRITE, t2 WRITE; +truncate t1; +truncate t2; +ERROR HY000: Cannot truncate a versioned table +unlock tables; drop database test; create database test; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index 88411468516..a9e2429b7c4 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -341,15 +341,6 @@ create or replace trigger tr before insert on t2 for each row select count(*) from t1 into @a; insert into t2 values (1); ---echo # MDEV-14741 Assertion `(trx)->start_file == 0' failed in row_truncate_table_for_mysql() -create or replace table t1 (i int) with system versioning -partition by system_time interval 1 hour ( - partition p1 history, - partition pn current); -set autocommit= off; -truncate table t1; -set autocommit= on; - --echo # MDEV-14747 ALTER PARTITION BY SYSTEM_TIME after LOCK TABLES create or replace table t1 (x int) with system versioning; lock table t1 write; diff --git a/mysql-test/suite/versioning/t/truncate.test b/mysql-test/suite/versioning/t/truncate.test index 1727c7787ef..360c73bb8ed 100644 --- a/mysql-test/suite/versioning/t/truncate.test +++ b/mysql-test/suite/versioning/t/truncate.test @@ -117,5 +117,33 @@ call pr; drop procedure pr; drop table t1; +--echo # MDEV-15966 Behavior for TRUNCATE versioned table is not documented and not covered by tests +create or replace table t1 (id int); +create or replace table t2 (id int) with system versioning; + +-- echo # force cleaning table shares +flush tables t1, t2; + +truncate table t1; +--error ER_TRUNCATE_ILLEGAL_VERS +truncate table t2; + +-- echo # fetch table shares +describe t1; +describe t2; + +truncate table t1; +--error ER_TRUNCATE_ILLEGAL_VERS +truncate table t2; + +--echo # enter locked tables mode +lock tables t1 WRITE, t2 WRITE; + +truncate t1; +--error ER_TRUNCATE_ILLEGAL_VERS +truncate t2; + +unlock tables; + drop database test; create database test; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index feb47f9af94..94737d48e64 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7931,3 +7931,5 @@ ER_PERIOD_CONSTRAINT_DROP eng "Can't DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this" ER_TOO_LONG_KEYPART 42000 S1009 eng "Specified key part was too long; max key part length is %u bytes" +ER_TRUNCATE_ILLEGAL_VERS + eng "Cannot truncate a versioned table" diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 389276d0bcf..c0de635579a 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -275,6 +275,9 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref, bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, bool *hton_can_recreate) { + handlerton *hton; + bool versioned; + bool sequence= false; TABLE *table= NULL; DBUG_ENTER("Sql_cmd_truncate_table::lock_table"); @@ -302,43 +305,43 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, table_ref->table_name.str, NULL))) DBUG_RETURN(TRUE); - *hton_can_recreate= ha_check_storage_engine_flag(table->file->ht, - HTON_CAN_RECREATE); + versioned= table->versioned(); + hton= table->file->ht; table_ref->mdl_request.ticket= table->mdl_ticket; } else { - handlerton *hton; - bool is_sequence; - - /* Acquire an exclusive lock. */ DBUG_ASSERT(table_ref->next_global == NULL); if (lock_table_names(thd, table_ref, NULL, thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(TRUE); - if (!ha_table_exists(thd, &table_ref->db, &table_ref->table_name, - &hton, &is_sequence) || - hton == view_pseudo_hton) + TABLE_SHARE *share= tdc_acquire_share(thd, table_ref, GTS_TABLE | GTS_VIEW); + if (share == NULL) + DBUG_RETURN(TRUE); + DBUG_ASSERT(share != (TABLE_SHARE*)1); + + versioned= share->versioned; + sequence= share->table_type == TABLE_TYPE_SEQUENCE; + hton= share->db_type(); + + tdc_release_share(share); + + if (hton == view_pseudo_hton) { my_error(ER_NO_SUCH_TABLE, MYF(0), table_ref->db.str, table_ref->table_name.str); DBUG_RETURN(TRUE); } + } - if (!hton) - { - /* - The table exists, but its storage engine is unknown, perhaps not - loaded at the moment. We need to open and parse the frm to know the - storage engine in question, so let's proceed with the truncation and - try to open the table. This will produce the correct error message - about unknown engine. - */ - *hton_can_recreate= false; - } - else - *hton_can_recreate= !is_sequence && hton->flags & HTON_CAN_RECREATE; + *hton_can_recreate= !sequence + && ha_check_storage_engine_flag(hton, HTON_CAN_RECREATE); + + if (versioned) + { + my_error(ER_TRUNCATE_ILLEGAL_VERS, MYF(0)); + DBUG_RETURN(TRUE); } /*