diff --git a/mysql-test/r/bdb-crash.result b/mysql-test/r/bdb-crash.result index 8f5b8c08f1d..778890e85e3 100644 --- a/mysql-test/r/bdb-crash.result +++ b/mysql-test/r/bdb-crash.result @@ -30,3 +30,10 @@ ChargeID ServiceID ChargeDate ChargeAmount FedTaxes ProvTaxes ChargeStatus Charg 1 1 2001-03-01 1.00 1.00 1.00 New blablabla NULL now 2 1 2001-03-01 1.00 1.00 1.00 New NULL NULL now drop table t1; +create table t1 (a int) engine=bdb; +set autocommit=0; +insert into t1 values(1); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status Operation need committed state +drop table t1; diff --git a/mysql-test/t/bdb-crash.test b/mysql-test/t/bdb-crash.test index fffed379e79..cea69df6993 100644 --- a/mysql-test/t/bdb-crash.test +++ b/mysql-test/t/bdb-crash.test @@ -36,3 +36,16 @@ INSERT INTO t1 VALUES(NULL,1,'2001-03-01',1,1,1,'New',NULL,NULL,'now'); select * from t1; drop table t1; + +# +# Test for bug #2342 "Running ANALYZE TABLE on bdb table +# inside a transaction hangs server thread" +# + +create table t1 (a int) engine=bdb; + +set autocommit=0; +insert into t1 values(1); +analyze table t1; +drop table t1; + diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 70ecc61bfb8..4a1ce43cf70 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -2125,6 +2125,35 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt) { DB_BTREE_STAT *stat=0; uint i; + DB_TXN_STAT *txn_stat_ptr= 0; + + if (!db_env->txn_stat(db_env, &txn_stat_ptr, 0) && + txn_stat_ptr && txn_stat_ptr->st_nactive>=2) + { + DB_TXN_ACTIVE *atxn_stmt= 0, *atxn_all= 0; + + DB_TXN *txn_all= (DB_TXN*) thd->transaction.all.bdb_tid; + u_int32_t all_id= txn_all->id(txn_all); + + DB_TXN *txn_stmt= (DB_TXN*) thd->transaction.stmt.bdb_tid; + u_int32_t stmt_id= txn_stmt->id(txn_stmt); + + DB_TXN_ACTIVE *cur= txn_stat_ptr->st_txnarray; + DB_TXN_ACTIVE *end= cur + txn_stat_ptr->st_nactive; + for (; cur!=end && (!atxn_stmt || !atxn_all); cur++) + { + if (cur->txnid==all_id) atxn_all= cur; + if (cur->txnid==stmt_id) atxn_stmt= cur; + } + + if (atxn_stmt && atxn_all && + log_compare(&atxn_stmt->lsn,&atxn_all->lsn)) + { + free(txn_stat_ptr); + return HA_ADMIN_REJECT; + } + free(txn_stat_ptr); + } for (i=0 ; i < table->keys ; i++) { diff --git a/sql/handler.h b/sql/handler.h index 35a93709e98..26fb762a9b5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -41,6 +41,7 @@ #define HA_ADMIN_CORRUPT -3 #define HA_ADMIN_INTERNAL_ERROR -4 #define HA_ADMIN_INVALID -5 +#define HA_ADMIN_REJECT -6 /* Bits in table_flags() to show what database can do */ #define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record diff --git a/sql/sql_table.cc b/sql/sql_table.cc index be3615c71ce..48007b44f43 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1666,6 +1666,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, protocol->store("Operation failed",16, system_charset_info); break; + case HA_ADMIN_REJECT: + protocol->store("status", 6, system_charset_info); + protocol->store("Operation need committed state",30, system_charset_info); + open_for_modify= false; + break; + case HA_ADMIN_ALREADY_DONE: protocol->store("status", 6, system_charset_info); protocol->store("Table is already up to date", 27, system_charset_info);