Fixed lp:997460 Truncate table on partitioned Aria table fails with ER_ILLEGAL_HA
Fix is done by doing an autocommit in truncate table inside Aria storage/maria/ha_maria.cc: Force a commit for TRUNCATE TABLE inside lock tables Check that we don't call TRUNCATE with concurrent inserts going on. Make ha_maria::implict_commit faster when we don't have Aria tables in the transaction. (Most of the patch is just re-indentation because I removed an if level)
This commit is contained in:
parent
b1485a4780
commit
d4d3ca204f
@ -2542,8 +2542,12 @@ drop table t1;
|
|||||||
create table t1 (a int) engine=aria transactional=1;
|
create table t1 (a int) engine=aria transactional=1;
|
||||||
insert into t1 values (1);
|
insert into t1 values (1);
|
||||||
lock table t1 write concurrent;
|
lock table t1 write concurrent;
|
||||||
delete from t1;
|
delete from t1 where a>0;
|
||||||
ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT
|
ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT
|
||||||
|
delete from t1;
|
||||||
|
ERROR 42000: The storage engine for the table doesn't support TRUNCATE in WRITE CONCURRENT
|
||||||
|
truncate t1;
|
||||||
|
ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
|
||||||
unlock tables;
|
unlock tables;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
|
create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
|
||||||
|
@ -1805,7 +1805,11 @@ insert into t1 values (1);
|
|||||||
lock table t1 write concurrent;
|
lock table t1 write concurrent;
|
||||||
# should be fixed with fully implemented versioning
|
# should be fixed with fully implemented versioning
|
||||||
--error ER_CHECK_NOT_IMPLEMENTED
|
--error ER_CHECK_NOT_IMPLEMENTED
|
||||||
|
delete from t1 where a>0;
|
||||||
|
--error ER_CHECK_NOT_IMPLEMENTED
|
||||||
delete from t1;
|
delete from t1;
|
||||||
|
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
|
||||||
|
truncate t1;
|
||||||
unlock tables;
|
unlock tables;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
37
mysql-test/suite/maria/truncate.result
Normal file
37
mysql-test/suite/maria/truncate.result
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
CREATE TABLE t1 ( i INT ) ENGINE=Aria PARTITION BY HASH(i) PARTITIONS 2;
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1 ( i INT ) ENGINE=Aria;
|
||||||
|
CREATE TABLE t2 ( i INT ) ENGINE=Aria;
|
||||||
|
insert into t1 values(1);
|
||||||
|
lock table t1 write;
|
||||||
|
truncate table t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
insert into t1 values(2);
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
1
|
||||||
|
truncate table t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
insert into t1 values(3);
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
1
|
||||||
|
select * from t2;
|
||||||
|
ERROR HY000: Table 't2' was not locked with LOCK TABLES
|
||||||
|
unlock tables;
|
||||||
|
insert into t1 values(4);
|
||||||
|
select * from t1;
|
||||||
|
i
|
||||||
|
3
|
||||||
|
4
|
||||||
|
truncate t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
count(*)
|
||||||
|
0
|
||||||
|
drop table t1,t2;
|
47
mysql-test/suite/maria/truncate.test
Normal file
47
mysql-test/suite/maria/truncate.test
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#
|
||||||
|
# Testing of potential problems in Aria
|
||||||
|
#
|
||||||
|
|
||||||
|
-- source include/have_maria.inc
|
||||||
|
-- source include/have_partition.inc
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
--disable_query_log
|
||||||
|
drop table if exists t1,t2;
|
||||||
|
--enable_query_log
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
#
|
||||||
|
# LP:997460 truncate table on partitioned Aria table fails with ER_ILLEGAL_HA
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE TABLE t1 ( i INT ) ENGINE=Aria PARTITION BY HASH(i) PARTITIONS 2;
|
||||||
|
SET AUTOCOMMIT = 0;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Other truncate tests
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE TABLE t1 ( i INT ) ENGINE=Aria;
|
||||||
|
CREATE TABLE t2 ( i INT ) ENGINE=Aria;
|
||||||
|
insert into t1 values(1);
|
||||||
|
lock table t1 write;
|
||||||
|
truncate table t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
insert into t1 values(2);
|
||||||
|
select count(*) from t1;
|
||||||
|
truncate table t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
insert into t1 values(3);
|
||||||
|
select count(*) from t1;
|
||||||
|
# Check that locking is still working
|
||||||
|
--error 1100
|
||||||
|
select * from t2;
|
||||||
|
unlock tables;
|
||||||
|
insert into t1 values(4);
|
||||||
|
select * from t1;
|
||||||
|
truncate t1;
|
||||||
|
select count(*) from t1;
|
||||||
|
drop table t1,t2;
|
@ -2537,9 +2537,10 @@ int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size)
|
|||||||
|
|
||||||
int ha_maria::delete_all_rows()
|
int ha_maria::delete_all_rows()
|
||||||
{
|
{
|
||||||
#ifdef EXTRA_DEBUG
|
|
||||||
THD *thd= table->in_use;
|
THD *thd= table->in_use;
|
||||||
TRN *trn= file->trn;
|
TRN *trn= file->trn;
|
||||||
|
CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("TRUNCATE in WRITE CONCURRENT");
|
||||||
|
#ifdef EXTRA_DEBUG
|
||||||
if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED))
|
if (trn && ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED))
|
||||||
{
|
{
|
||||||
trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED |
|
trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED |
|
||||||
@ -2548,16 +2549,19 @@ int ha_maria::delete_all_rows()
|
|||||||
(uchar*) thd->query(), thd->query_length());
|
(uchar*) thd->query(), thd->query_length());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (file->s->now_transactional &&
|
/*
|
||||||
((table->in_use->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
|
If we are under LOCK TABLES, we have to do a commit as
|
||||||
table->in_use->locked_tables_mode))
|
delete_all_rows() can't be rolled back
|
||||||
|
*/
|
||||||
|
if (table->in_use->locked_tables_mode && trn &&
|
||||||
|
trnman_has_locked_tables(trn))
|
||||||
{
|
{
|
||||||
/*
|
int error;
|
||||||
We are not in autocommit mode or user have done LOCK TABLES.
|
if ((error= implicit_commit(thd, 1)))
|
||||||
We must do the delete row by row to be able to rollback the command
|
return error;
|
||||||
*/
|
|
||||||
return HA_ERR_WRONG_COMMAND;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note that this can't be rolled back */
|
||||||
return maria_delete_all_rows(file);
|
return maria_delete_all_rows(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2775,10 +2779,11 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
|||||||
#error this method should be removed
|
#error this method should be removed
|
||||||
#endif
|
#endif
|
||||||
TRN *trn;
|
TRN *trn;
|
||||||
int error= 0;
|
int error;
|
||||||
|
uint locked_tables;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
DBUG_ENTER("ha_maria::implicit_commit");
|
DBUG_ENTER("ha_maria::implicit_commit");
|
||||||
if (!maria_hton)
|
if (!maria_hton || !(trn= THD_TRN))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
||||||
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
|
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
|
||||||
@ -2792,60 +2797,59 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
|||||||
DBUG_PRINT("info", ("locked_tables, skipping"));
|
DBUG_PRINT("info", ("locked_tables, skipping"));
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
if ((trn= THD_TRN) != NULL)
|
locked_tables= trnman_has_locked_tables(trn);
|
||||||
|
error= 0;
|
||||||
|
if (unlikely(ma_commit(trn)))
|
||||||
|
error= 1;
|
||||||
|
if (!new_trn)
|
||||||
{
|
{
|
||||||
uint locked_tables= trnman_has_locked_tables(trn);
|
|
||||||
if (unlikely(ma_commit(trn)))
|
|
||||||
error= 1;
|
|
||||||
if (!new_trn)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
To be extra safe, we should also reset file->trn for all open
|
|
||||||
tables as some calls, like extra() may access it. We take care
|
|
||||||
of this in extra() by resetting file->trn if THD_TRN is 0.
|
|
||||||
*/
|
|
||||||
THD_TRN= NULL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
We need to create a new transaction and put it in THD_TRN. Indeed,
|
To be extra safe, we should also reset file->trn for all open
|
||||||
tables may be under LOCK TABLES, and so they will start the next
|
tables as some calls, like extra() may access it. We take care
|
||||||
statement assuming they have a trn (see ha_maria::start_stmt()).
|
of this in extra() by resetting file->trn if THD_TRN is 0.
|
||||||
*/
|
*/
|
||||||
trn= trnman_new_trn(& thd->transaction.wt);
|
THD_TRN= NULL;
|
||||||
THD_TRN= trn;
|
goto end;
|
||||||
if (unlikely(trn == NULL))
|
}
|
||||||
|
/*
|
||||||
|
We need to create a new transaction and put it in THD_TRN. Indeed,
|
||||||
|
tables may be under LOCK TABLES, and so they will start the next
|
||||||
|
statement assuming they have a trn (see ha_maria::start_stmt()).
|
||||||
|
*/
|
||||||
|
trn= trnman_new_trn(& thd->transaction.wt);
|
||||||
|
THD_TRN= trn;
|
||||||
|
if (unlikely(trn == NULL))
|
||||||
|
{
|
||||||
|
error= HA_ERR_OUT_OF_MEM;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Move all locked tables to the new transaction
|
||||||
|
We must do it here as otherwise file->thd and file->state may be
|
||||||
|
stale pointers. We can't do this in start_stmt() as we don't know
|
||||||
|
when we should call _ma_setup_live_state() and in some cases, like
|
||||||
|
in check table, we use the table without calling start_stmt().
|
||||||
|
*/
|
||||||
|
for (table=thd->open_tables; table ; table=table->next)
|
||||||
|
{
|
||||||
|
if (table->db_stat && table->file->ht == maria_hton)
|
||||||
{
|
{
|
||||||
error= HA_ERR_OUT_OF_MEM;
|
MARIA_HA *handler= ((ha_maria*) table->file)->file;
|
||||||
goto end;
|
if (handler->s->base.born_transactional)
|
||||||
}
|
|
||||||
/*
|
|
||||||
Move all locked tables to the new transaction
|
|
||||||
We must do it here as otherwise file->thd and file->state may be
|
|
||||||
stale pointers. We can't do this in start_stmt() as we don't know
|
|
||||||
when we should call _ma_setup_live_state() and in some cases, like
|
|
||||||
in check table, we use the table without calling start_stmt().
|
|
||||||
*/
|
|
||||||
for (table=thd->open_tables; table ; table=table->next)
|
|
||||||
{
|
|
||||||
if (table->db_stat && table->file->ht == maria_hton)
|
|
||||||
{
|
{
|
||||||
MARIA_HA *handler= ((ha_maria*) table->file)->file;
|
_ma_set_trn_for_table(handler, trn);
|
||||||
if (handler->s->base.born_transactional)
|
/* If handler uses versioning */
|
||||||
|
if (handler->s->lock_key_trees)
|
||||||
{
|
{
|
||||||
_ma_set_trn_for_table(handler, trn);
|
if (_ma_setup_live_state(handler))
|
||||||
/* If handler uses versioning */
|
error= HA_ERR_OUT_OF_MEM;
|
||||||
if (handler->s->lock_key_trees)
|
|
||||||
{
|
|
||||||
if (_ma_setup_live_state(handler))
|
|
||||||
error= HA_ERR_OUT_OF_MEM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* This is just a commit, tables stay locked if they were: */
|
|
||||||
trnman_reset_locked_tables(trn, locked_tables);
|
|
||||||
}
|
}
|
||||||
|
/* This is just a commit, tables stay locked if they were: */
|
||||||
|
trnman_reset_locked_tables(trn, locked_tables);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user