Commit 88accb77 authored by Michael Widenius's avatar Michael Widenius

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)
parent 598bb174
...@@ -2542,8 +2542,12 @@ drop table t1; ...@@ -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); ...@@ -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;
......
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;
#
# 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) ...@@ -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() ...@@ -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) ...@@ -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) ...@@ -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)) }
{ /*
error= HA_ERR_OUT_OF_MEM; We need to create a new transaction and put it in THD_TRN. Indeed,
goto end; tables may be under LOCK TABLES, and so they will start the next
} statement assuming they have a trn (see ha_maria::start_stmt()).
/* */
Move all locked tables to the new transaction trn= trnman_new_trn(& thd->transaction.wt);
We must do it here as otherwise file->thd and file->state may be THD_TRN= trn;
stale pointers. We can't do this in start_stmt() as we don't know if (unlikely(trn == NULL))
when we should call _ma_setup_live_state() and in some cases, like {
in check table, we use the table without calling start_stmt(). error= HA_ERR_OUT_OF_MEM;
*/ goto end;
for (table=thd->open_tables; table ; table=table->next) }
/*
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)
{ {
if (table->db_stat && table->file->ht == maria_hton) MARIA_HA *handler= ((ha_maria*) table->file)->file;
if (handler->s->base.born_transactional)
{ {
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);
} }
......
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