diff --git a/mysql-test/suite/innodb/r/insert_into_empty.result b/mysql-test/suite/innodb/r/insert_into_empty.result index eedfb6819294c..d17f24bd7d52c 100644 --- a/mysql-test/suite/innodb/r/insert_into_empty.result +++ b/mysql-test/suite/innodb/r/insert_into_empty.result @@ -214,6 +214,21 @@ WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; TABLE_ROWS AVG_ROW_LENGTH>0 3 1 DROP TABLE t1; +# +# MDEV-29975 InnoDB fails to release savepoint during bulk insert +# +CREATE TABLE t (c INT KEY) ENGINE=InnoDB; +begin; +INSERT INTO t VALUES (0,0); +ERROR 21S01: Column count doesn't match value count at row 1 +SAVEPOINT a; +INSERT INTO t VALUES (0),(0); +ERROR HY000: Got error 1 "Operation not permitted" during COMMIT +SAVEPOINT a; +commit; +SELECT * FROM t; +c +DROP TABLE t; # End of 10.6 tests # # MDEV-26947 UNIQUE column checks fail in InnoDB resulting diff --git a/mysql-test/suite/innodb/r/undo_truncate.result b/mysql-test/suite/innodb/r/undo_truncate.result index 5be1e5c342661..48b184f07c74f 100644 --- a/mysql-test/suite/innodb/r/undo_truncate.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -1,5 +1,10 @@ SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +=== information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === +Space_Name Page_Size Zip_Size Path +innodb_undo001 DEFAULT DEFAULT MYSQLD_DATADIR//undo001 +innodb_undo002 DEFAULT DEFAULT MYSQLD_DATADIR//undo002 +innodb_temporary DEFAULT DEFAULT MYSQLD_DATADIR/ibtmp1 create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; connect con1,localhost,root,,; diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test index ee32a2d7cacc8..8f7eb3a6c1f96 100644 --- a/mysql-test/suite/innodb/t/insert_into_empty.test +++ b/mysql-test/suite/innodb/t/insert_into_empty.test @@ -235,6 +235,20 @@ SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; DROP TABLE t1; +--echo # +--echo # MDEV-29975 InnoDB fails to release savepoint during bulk insert +--echo # +CREATE TABLE t (c INT KEY) ENGINE=InnoDB; +begin; +--error ER_WRONG_VALUE_COUNT_ON_ROW +INSERT INTO t VALUES (0,0); +SAVEPOINT a; +--error ER_ERROR_DURING_COMMIT +INSERT INTO t VALUES (0),(0); +SAVEPOINT a; +commit; +SELECT * FROM t; +DROP TABLE t; --echo # End of 10.6 tests --echo # diff --git a/mysql-test/suite/innodb/t/undo_truncate.opt b/mysql-test/suite/innodb/t/undo_truncate.opt index 1459ec5db74a4..5e331e832fd3d 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.opt +++ b/mysql-test/suite/innodb/t/undo_truncate.opt @@ -1,2 +1,3 @@ --innodb-buffer-pool-size=24M --innodb-immediate-scrub-data-uncompressed=ON +--loose-innodb-sys-tablespaces diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test index 19829ce21e75d..496eccb002e43 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.test +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -15,6 +15,9 @@ call mtr.add_suppression("InnoDB: Trying to delete tablespace.*pending operation SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +LET $MYSQLD_DATADIR = `select @@datadir`; +LET $INNODB_PAGE_SIZE = `select @@innodb_page_size`; +--source suite/innodb/include/show_i_s_tablespaces.inc #----------------------------------------------------------------------------- # # Perform DML action using multiple clients and multiple undo tablespace. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index bf1d5d83afb41..40adc90f7f1cb 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4455,6 +4455,25 @@ innobase_commit_ordered( DBUG_VOID_RETURN; } +/** Mark the end of a statement. +@param trx transaction +@return whether an error occurred */ +static bool end_of_statement(trx_t *trx) +{ + trx_mark_sql_stat_end(trx); + if (UNIV_LIKELY(trx->error_state == DB_SUCCESS)) + return false; + + trx_savept_t savept; + savept.least_undo_no= 0; + trx->rollback(&savept); + /* MariaDB will roll back the entire transaction. */ + trx->bulk_insert= false; + trx->last_sql_stat_start.least_undo_no= 0; + trx->savepoints_discard(); + return true; +} + /*****************************************************************//** Commits a transaction in an InnoDB database or marks an SQL statement ended. @@ -4531,10 +4550,7 @@ innobase_commit( /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement */ - - trx_mark_sql_stat_end(trx); - if (UNIV_UNLIKELY(trx->error_state != DB_SUCCESS)) { - trx_rollback_for_mysql(trx); + if (UNIV_UNLIKELY(end_of_statement(trx))) { DBUG_RETURN(1); } } @@ -16954,10 +16970,7 @@ innobase_xa_prepare( /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement */ - - trx_mark_sql_stat_end(trx); - if (UNIV_UNLIKELY(trx->error_state != DB_SUCCESS)) { - trx_rollback_for_mysql(trx); + if (UNIV_UNLIKELY(end_of_statement(trx))) { return 1; } } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 9510a4a8bfcfd..3b537afef4019 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6142,8 +6142,13 @@ static int i_s_sys_tablespaces_fill(THD *thd, const fil_space_t &s, TABLE *t) OK(f->store(name.data(), name.size(), system_charset_info)); f->set_notnull(); } - else - f->set_notnull(); + else if (srv_is_undo_tablespace(s.id)) + { + char name[15]; + snprintf(name, sizeof name, "innodb_undo%03u", + (s.id - srv_undo_space_id_start + 1)); + OK(f->store(name, strlen(name), system_charset_info)); + } else f->set_notnull(); } fields[SYS_TABLESPACES_NAME]->set_null(); diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index 45dc78b4440d3..99cf1364192a1 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -557,9 +557,13 @@ trx_release_savepoint_for_mysql( if (savep != NULL) { trx_roll_savepoint_free(trx, savep); + return DB_SUCCESS; + } else if (trx->last_sql_stat_start.least_undo_no == 0) { + /* Bulk insert could have discarded savepoints */ + return DB_SUCCESS; } - return(savep != NULL ? DB_SUCCESS : DB_NO_SAVEPOINT); + return DB_NO_SAVEPOINT; } /*******************************************************************//**