diff --git a/innobase/include/read0read.h b/innobase/include/read0read.h index b5edcefb544..7a91248cf7f 100644 --- a/innobase/include/read0read.h +++ b/innobase/include/read0read.h @@ -136,6 +136,9 @@ struct cursor_view_struct{ /* Memory heap for the cursor view */ read_view_t* read_view; /* Consistent read view of the cursor*/ + ulint n_mysql_tables_in_use; + /* number of Innobase tables used in the + processing of this cursor */ }; #ifndef UNIV_NONINL diff --git a/innobase/read/read0read.c b/innobase/read/read0read.c index 334f9a8a85a..dc1ae2f1a16 100644 --- a/innobase/read/read0read.c +++ b/innobase/read/read0read.c @@ -286,6 +286,11 @@ read_cursor_view_create_for_mysql( curview = (cursor_view_t*) mem_heap_alloc(heap, sizeof(cursor_view_t)); curview->heap = heap; + /* Drop cursor tables from consideration when evaluating the need of + auto-commit */ + curview->n_mysql_tables_in_use = cr_trx->n_mysql_tables_in_use; + cr_trx->n_mysql_tables_in_use = 0; + mutex_enter(&kernel_mutex); curview->read_view = read_view_create_low( @@ -360,6 +365,10 @@ read_cursor_view_close_for_mysql( ut_a(curview->read_view); ut_a(curview->heap); + /* Add cursor's tables to the global count of active tables that + belong to this transaction */ + trx->n_mysql_tables_in_use += curview->n_mysql_tables_in_use; + mutex_enter(&kernel_mutex); read_view_close(curview->read_view); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 15881cb8c5d..57689520bfb 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3101,12 +3101,6 @@ row_search_for_mysql( "InnoDB: how you can resolve the problem.\n", prebuilt->table->name); - /* Restore a global read view back to a transaction. This - forces MySQL always to set a cursor view before fetch from - a cursor. */ - - trx->read_view = trx->global_read_view; - return(DB_ERROR); } @@ -4098,12 +4092,6 @@ normal_return: } func_exit: - /* Restore a global read view back to a transaction. This - forces MySQL always to set a cursor view before fetch from - a cursor. */ - - trx->read_view = trx->global_read_view; - trx->op_info = ""; if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 026bc0da13d..0a01c08c916 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2146,6 +2146,15 @@ innobase_close_connection( ut_a(trx); + if (trx->active_trans == 0 + && trx->conc_state != TRX_NOT_STARTED) { + + fprintf(stderr, +"InnoDB: Error: trx->active_trans == 0\n" +"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n"); + } + + if (trx->conc_state != TRX_NOT_STARTED && global_system_variables.log_warnings) sql_print_warning("MySQL is closing a connection that has an active " diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 15cba906f6b..75f57436c38 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -14179,6 +14179,66 @@ static void test_bug11901() myquery(rc); } +/* Bug#12243: multiple cursors, crash in a fetch after commit. */ + +static void test_bug12243() +{ + MYSQL_STMT *stmt1, *stmt2; + int rc; + const char *stmt_text; + ulong type; + + myheader("test_bug12243"); + + if (! have_innodb) + { + if (!opt_silent) + printf("This test requires InnoDB.\n"); + return; + } + + /* create tables */ + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int) engine=InnoDB"); + rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)"); + myquery(rc); + mysql_autocommit(mysql, FALSE); + /* create statement */ + stmt1= mysql_stmt_init(mysql); + stmt2= mysql_stmt_init(mysql); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + stmt_text= "select a from t1"; + + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + check_execute(stmt1, rc); + rc= mysql_stmt_fetch(stmt1); + check_execute(stmt1, rc); + + rc= mysql_stmt_prepare(stmt2, stmt_text, strlen(stmt_text)); + check_execute(stmt2, rc); + rc= mysql_stmt_execute(stmt2); + check_execute(stmt2, rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + rc= mysql_stmt_close(stmt1); + check_execute(stmt1, rc); + rc= mysql_commit(mysql); + myquery(rc); + rc= mysql_stmt_fetch(stmt2); + check_execute(stmt2, rc); + + mysql_stmt_close(stmt2); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + mysql_autocommit(mysql, TRUE); /* restore default */ +} + /* Read and parse arguments and MySQL options from my.cnf */ @@ -14427,6 +14487,7 @@ static struct my_tests_st my_tests[]= { { "test_bug12001", test_bug12001 }, { "test_bug11909", test_bug11909 }, { "test_bug11901", test_bug11901 }, + { "test_bug12243", test_bug12243 }, { 0, 0 } };