summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/CMakeLists.txt2
-rw-r--r--mysql-test/suite/innodb/r/foreign_key.result10
-rw-r--r--mysql-test/suite/innodb/r/xa_debug.result310
-rw-r--r--mysql-test/suite/innodb/t/foreign_key.test9
-rw-r--r--mysql-test/suite/innodb/t/xa_debug.test45
-rw-r--r--sql/handler.cc1
-rw-r--r--storage/innobase/dict/dict0dict.cc18
-rw-r--r--storage/innobase/include/trx0trx.h5
-rw-r--r--storage/innobase/include/trx0trx.ic3
-rw-r--r--storage/innobase/include/trx0types.h7
-rw-r--r--storage/innobase/lock/lock0lock.cc5
-rw-r--r--storage/innobase/trx/trx0roll.cc6
-rw-r--r--storage/innobase/trx/trx0trx.cc34
-rw-r--r--storage/xtradb/dict/dict0dict.cc18
-rw-r--r--storage/xtradb/include/trx0trx.h5
-rw-r--r--storage/xtradb/include/trx0trx.ic3
-rw-r--r--storage/xtradb/include/trx0types.h7
-rw-r--r--storage/xtradb/lock/lock0lock.cc5
-rw-r--r--storage/xtradb/trx/trx0roll.cc6
-rw-r--r--storage/xtradb/trx/trx0trx.cc34
20 files changed, 495 insertions, 38 deletions
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index c760a9dbf14..40df176c6e6 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
-# Copyright (c) 2008, 2018, MariaDB Corporation
+# Copyright (c) 2008, 2019, MariaDB Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result
index 3c881b43504..e56e5308909 100644
--- a/mysql-test/suite/innodb/r/foreign_key.result
+++ b/mysql-test/suite/innodb/r/foreign_key.result
@@ -101,7 +101,15 @@ ALTER IGNORE TABLE t1 ADD FOREIGN KEY (a) REFERENCES t2 (b);
ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed")
SHOW WARNINGS;
Level Code Message
-Warning 150 Alter table test/#sql-temporary with foreign key constraint failed. Referenced table `test`.`t2` not found in the data dictionary near 'FOREIGN KEY (a) REFERENCES t2 (b)'.
+Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Referenced table `test`.`t2` not found in the data dictionary near 'FOREIGN KEY (a) REFERENCES t2 (b)'.
Error 1005 Can't create table `test`.`#sql-temporary` (errno: 150 "Foreign key constraint is incorrectly formed")
Warning 1215 Cannot add foreign key constraint
DROP TABLE t1;
+#
+# MDEV-18139 ALTER IGNORE ... ADD FOREIGN KEY causes bogus error
+#
+CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY(f1)) ENGINE=InnoDB;
+CREATE TABLE t2 (f INT, KEY(f)) ENGINE=InnoDB;
+ALTER TABLE t1 ADD FOREIGN KEY (f2) REFERENCES t2 (f);
+ALTER IGNORE TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f1);
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/innodb/r/xa_debug.result b/mysql-test/suite/innodb/r/xa_debug.result
new file mode 100644
index 00000000000..43a3b299468
--- /dev/null
+++ b/mysql-test/suite/innodb/r/xa_debug.result
@@ -0,0 +1,310 @@
+call mtr.add_suppression("Found 50 prepared XA transactions");
+create table t1 (a int) engine=innodb;
+insert into t1 values(1);
+xa start 'test50';
+insert into t1 values(1);
+xa end 'test50';
+xa prepare 'test50';
+xa start 'test49';
+insert into t1 values(1);
+xa end 'test49';
+xa prepare 'test49';
+xa start 'test48';
+insert into t1 values(1);
+xa end 'test48';
+xa prepare 'test48';
+xa start 'test47';
+insert into t1 values(1);
+xa end 'test47';
+xa prepare 'test47';
+xa start 'test46';
+insert into t1 values(1);
+xa end 'test46';
+xa prepare 'test46';
+xa start 'test45';
+insert into t1 values(1);
+xa end 'test45';
+xa prepare 'test45';
+xa start 'test44';
+insert into t1 values(1);
+xa end 'test44';
+xa prepare 'test44';
+xa start 'test43';
+insert into t1 values(1);
+xa end 'test43';
+xa prepare 'test43';
+xa start 'test42';
+insert into t1 values(1);
+xa end 'test42';
+xa prepare 'test42';
+xa start 'test41';
+insert into t1 values(1);
+xa end 'test41';
+xa prepare 'test41';
+xa start 'test40';
+insert into t1 values(1);
+xa end 'test40';
+xa prepare 'test40';
+xa start 'test39';
+insert into t1 values(1);
+xa end 'test39';
+xa prepare 'test39';
+xa start 'test38';
+insert into t1 values(1);
+xa end 'test38';
+xa prepare 'test38';
+xa start 'test37';
+insert into t1 values(1);
+xa end 'test37';
+xa prepare 'test37';
+xa start 'test36';
+insert into t1 values(1);
+xa end 'test36';
+xa prepare 'test36';
+xa start 'test35';
+insert into t1 values(1);
+xa end 'test35';
+xa prepare 'test35';
+xa start 'test34';
+insert into t1 values(1);
+xa end 'test34';
+xa prepare 'test34';
+xa start 'test33';
+insert into t1 values(1);
+xa end 'test33';
+xa prepare 'test33';
+xa start 'test32';
+insert into t1 values(1);
+xa end 'test32';
+xa prepare 'test32';
+xa start 'test31';
+insert into t1 values(1);
+xa end 'test31';
+xa prepare 'test31';
+xa start 'test30';
+insert into t1 values(1);
+xa end 'test30';
+xa prepare 'test30';
+xa start 'test29';
+insert into t1 values(1);
+xa end 'test29';
+xa prepare 'test29';
+xa start 'test28';
+insert into t1 values(1);
+xa end 'test28';
+xa prepare 'test28';
+xa start 'test27';
+insert into t1 values(1);
+xa end 'test27';
+xa prepare 'test27';
+xa start 'test26';
+insert into t1 values(1);
+xa end 'test26';
+xa prepare 'test26';
+xa start 'test25';
+insert into t1 values(1);
+xa end 'test25';
+xa prepare 'test25';
+xa start 'test24';
+insert into t1 values(1);
+xa end 'test24';
+xa prepare 'test24';
+xa start 'test23';
+insert into t1 values(1);
+xa end 'test23';
+xa prepare 'test23';
+xa start 'test22';
+insert into t1 values(1);
+xa end 'test22';
+xa prepare 'test22';
+xa start 'test21';
+insert into t1 values(1);
+xa end 'test21';
+xa prepare 'test21';
+xa start 'test20';
+insert into t1 values(1);
+xa end 'test20';
+xa prepare 'test20';
+xa start 'test19';
+insert into t1 values(1);
+xa end 'test19';
+xa prepare 'test19';
+xa start 'test18';
+insert into t1 values(1);
+xa end 'test18';
+xa prepare 'test18';
+xa start 'test17';
+insert into t1 values(1);
+xa end 'test17';
+xa prepare 'test17';
+xa start 'test16';
+insert into t1 values(1);
+xa end 'test16';
+xa prepare 'test16';
+xa start 'test15';
+insert into t1 values(1);
+xa end 'test15';
+xa prepare 'test15';
+xa start 'test14';
+insert into t1 values(1);
+xa end 'test14';
+xa prepare 'test14';
+xa start 'test13';
+insert into t1 values(1);
+xa end 'test13';
+xa prepare 'test13';
+xa start 'test12';
+insert into t1 values(1);
+xa end 'test12';
+xa prepare 'test12';
+xa start 'test11';
+insert into t1 values(1);
+xa end 'test11';
+xa prepare 'test11';
+xa start 'test10';
+insert into t1 values(1);
+xa end 'test10';
+xa prepare 'test10';
+xa start 'test9';
+insert into t1 values(1);
+xa end 'test9';
+xa prepare 'test9';
+xa start 'test8';
+insert into t1 values(1);
+xa end 'test8';
+xa prepare 'test8';
+xa start 'test7';
+insert into t1 values(1);
+xa end 'test7';
+xa prepare 'test7';
+xa start 'test6';
+insert into t1 values(1);
+xa end 'test6';
+xa prepare 'test6';
+xa start 'test5';
+insert into t1 values(1);
+xa end 'test5';
+xa prepare 'test5';
+xa start 'test4';
+insert into t1 values(1);
+xa end 'test4';
+xa prepare 'test4';
+xa start 'test3';
+insert into t1 values(1);
+xa end 'test3';
+xa prepare 'test3';
+xa start 'test2';
+insert into t1 values(1);
+xa end 'test2';
+xa prepare 'test2';
+xa start 'test1';
+insert into t1 values(1);
+xa end 'test1';
+xa prepare 'test1';
+xa recover;
+formatID gtrid_length bqual_length data
+1 5 0 test1
+1 5 0 test2
+1 5 0 test3
+1 5 0 test4
+1 5 0 test5
+1 5 0 test6
+1 5 0 test7
+1 5 0 test8
+1 5 0 test9
+1 6 0 test10
+1 6 0 test11
+1 6 0 test12
+1 6 0 test13
+1 6 0 test14
+1 6 0 test15
+1 6 0 test16
+1 6 0 test17
+1 6 0 test18
+1 6 0 test19
+1 6 0 test20
+1 6 0 test21
+1 6 0 test22
+1 6 0 test23
+1 6 0 test24
+1 6 0 test25
+1 6 0 test26
+1 6 0 test27
+1 6 0 test28
+1 6 0 test29
+1 6 0 test30
+1 6 0 test31
+1 6 0 test32
+1 6 0 test33
+1 6 0 test34
+1 6 0 test35
+1 6 0 test36
+1 6 0 test37
+1 6 0 test38
+1 6 0 test39
+1 6 0 test40
+1 6 0 test41
+1 6 0 test42
+1 6 0 test43
+1 6 0 test44
+1 6 0 test45
+1 6 0 test46
+1 6 0 test47
+1 6 0 test48
+1 6 0 test49
+1 6 0 test50
+xa recover;
+formatID gtrid_length bqual_length data
+1 5 0 test1
+1 5 0 test2
+1 5 0 test3
+1 5 0 test4
+1 5 0 test5
+1 5 0 test6
+1 5 0 test7
+1 5 0 test8
+1 5 0 test9
+1 6 0 test10
+1 6 0 test11
+1 6 0 test12
+1 6 0 test13
+1 6 0 test14
+1 6 0 test15
+1 6 0 test16
+1 6 0 test17
+1 6 0 test18
+1 6 0 test19
+1 6 0 test20
+1 6 0 test21
+1 6 0 test22
+1 6 0 test23
+1 6 0 test24
+1 6 0 test25
+1 6 0 test26
+1 6 0 test27
+1 6 0 test28
+1 6 0 test29
+1 6 0 test30
+1 6 0 test31
+1 6 0 test32
+1 6 0 test33
+1 6 0 test34
+1 6 0 test35
+1 6 0 test36
+1 6 0 test37
+1 6 0 test38
+1 6 0 test39
+1 6 0 test40
+1 6 0 test41
+1 6 0 test42
+1 6 0 test43
+1 6 0 test44
+1 6 0 test45
+1 6 0 test46
+1 6 0 test47
+1 6 0 test48
+1 6 0 test49
+1 6 0 test50
+xa recover;
+formatID gtrid_length bqual_length data
+drop table t1;
diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test
index f4117d2d780..08fe44911b5 100644
--- a/mysql-test/suite/innodb/t/foreign_key.test
+++ b/mysql-test/suite/innodb/t/foreign_key.test
@@ -125,3 +125,12 @@ ALTER IGNORE TABLE t1 ADD FOREIGN KEY (a) REFERENCES t2 (b);
--replace_regex /#sql-[0-9_a-f-]*/#sql-temporary/
SHOW WARNINGS;
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-18139 ALTER IGNORE ... ADD FOREIGN KEY causes bogus error
+--echo #
+CREATE TABLE t1 (f1 INT, f2 INT, f3 INT, KEY(f1)) ENGINE=InnoDB;
+CREATE TABLE t2 (f INT, KEY(f)) ENGINE=InnoDB;
+ALTER TABLE t1 ADD FOREIGN KEY (f2) REFERENCES t2 (f);
+ALTER IGNORE TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f1);
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/innodb/t/xa_debug.test b/mysql-test/suite/innodb/t/xa_debug.test
new file mode 100644
index 00000000000..5724891bb65
--- /dev/null
+++ b/mysql-test/suite/innodb/t/xa_debug.test
@@ -0,0 +1,45 @@
+-- source include/have_innodb.inc
+-- source include/have_debug.inc
+-- source include/not_embedded.inc
+
+call mtr.add_suppression("Found 50 prepared XA transactions");
+create table t1 (a int) engine=innodb;
+insert into t1 values(1);
+
+let $trial = 50;
+while ($trial)
+{
+--connect (con$trial, localhost, root,,)
+let $st_pre = `select concat('test', $trial)`;
+eval xa start '$st_pre';
+insert into t1 values(1);
+eval xa end '$st_pre';
+eval xa prepare '$st_pre';
+dec $trial;
+}
+
+connection default;
+# Kill and restart the server.
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server 0
+-- source include/wait_until_disconnected.inc
+
+-- exec echo "restart:--debug_dbug=+d,min_xa_len" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+-- disable_reconnect
+--sorted_result
+xa recover;
+--sorted_result
+xa recover;
+--disable_query_log
+let $trial = 50;
+while ($trial)
+{
+let $st_pre = `select concat('test', $trial)`;
+eval xa commit '$st_pre';
+dec $trial;
+}
+--enable_query_log
+xa recover;
+drop table t1;
diff --git a/sql/handler.cc b/sql/handler.cc
index f307b3895bc..87331a41db6 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1949,6 +1949,7 @@ int ha_recover(HASH *commit_list)
for (info.len= MAX_XID_LIST_SIZE ;
info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
{
+ DBUG_EXECUTE_IF("min_xa_len", info.len = 16;);
info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0));
}
if (!info.list)
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 06c63fd7121..1e9d9f8d74e 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -4445,11 +4445,19 @@ dict_create_foreign_constraints_low(
}
orig = ptr;
- ptr = dict_accept(cs, ptr, "TABLE", &success);
-
- if (!success) {
-
- goto loop;
+ for (;;) {
+ ptr = dict_accept(cs, ptr, "TABLE", &success);
+ if (success) {
+ break;
+ }
+ ptr = dict_accept(cs, ptr, "ONLINE", &success);
+ if (success) {
+ continue;
+ }
+ ptr = dict_accept(cs, ptr, "IGNORE", &success);
+ if (!success) {
+ goto loop;
+ }
}
/* We are doing an ALTER TABLE: scan the table name we are altering */
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index fe16b8272b8..165ebe82df8 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -526,7 +526,7 @@ non-locking select */
ut_ad(!trx_is_autocommit_non_locking((t))); \
switch ((t)->state) { \
case TRX_STATE_PREPARED: \
- /* fall through */ \
+ case TRX_STATE_PREPARED_RECOVERED: \
case TRX_STATE_ACTIVE: \
case TRX_STATE_COMMITTED_IN_MEMORY: \
continue; \
@@ -719,6 +719,7 @@ struct trx_t{
TRX_STATE_NOT_STARTED
TRX_STATE_ACTIVE
TRX_STATE_PREPARED
+ TRX_STATE_PREPARED_RECOVERED (special case of TRX_STATE_PREPARED)
TRX_STATE_COMMITTED_IN_MEMORY (alias below COMMITTED)
Valid state transitions are:
diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic
index fa30e6229a3..0011f2ca74b 100644
--- a/storage/innobase/include/trx0trx.ic
+++ b/storage/innobase/include/trx0trx.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -49,6 +49,7 @@ trx_state_eq(
#ifdef UNIV_DEBUG
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
return(trx->state == state);
diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h
index 7ca95131328..a0b398fffa1 100644
--- a/storage/innobase/include/trx0types.h
+++ b/storage/innobase/include/trx0types.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -48,7 +49,11 @@ enum trx_que_t {
enum trx_state_t {
TRX_STATE_NOT_STARTED,
TRX_STATE_ACTIVE,
- TRX_STATE_PREPARED, /* Support for 2PC/XA */
+ /** XA PREPARE has been executed; only XA COMMIT or XA ROLLBACK
+ are possible */
+ TRX_STATE_PREPARED,
+ /** XA PREPARE transaction that was returned to ha_recover() */
+ TRX_STATE_PREPARED_RECOVERED,
TRX_STATE_COMMITTED_IN_MEMORY
};
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index f06fcd6c4d8..1ad5b9881b1 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -7908,7 +7908,8 @@ lock_trx_release_locks(
{
assert_trx_in_list(trx);
- if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+ if (trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) {
mutex_enter(&trx_sys->mutex);
ut_a(trx_sys->n_prepared_trx > 0);
trx_sys->n_prepared_trx--;
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 3fd71aff23a..af17cfe6be5 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2018, MariaDB Corporation.
+Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -203,6 +203,7 @@ trx_rollback_for_mysql(
return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
return(trx_rollback_for_mysql_low(trx));
@@ -255,6 +256,7 @@ trx_rollback_last_sql_stat_for_mysql(
return(err);
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
/* The statement rollback is only allowed on an ACTIVE
transaction, not a PREPARED or COMMITTED one. */
@@ -421,6 +423,7 @@ trx_rollback_to_savepoint_for_mysql(
return(trx_rollback_to_savepoint_for_mysql_low(
trx, savep, mysql_binlog_cache_pos));
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
/* The savepoint rollback is only allowed on an ACTIVE
transaction, not a PREPARED or COMMITTED one. */
@@ -710,6 +713,7 @@ fake_prepared:
}
return(FALSE);
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
goto func_exit;
case TRX_STATE_NOT_STARTED:
break;
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index f36aabba8b4..4175777cc61 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -314,6 +314,7 @@ trx_free_prepared(
trx_t* trx) /*!< in, own: trx object */
{
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)
|| (trx->is_recovered
&& (trx_state_eq(trx, TRX_STATE_ACTIVE)
|| trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY))
@@ -568,8 +569,7 @@ trx_resurrect_insert(
/* trx_start_low() is not called with resurrect, so need to initialize
start time here.*/
- if (trx->state == TRX_STATE_ACTIVE
- || trx->state == TRX_STATE_PREPARED) {
+ if (trx->state != TRX_STATE_COMMITTED_IN_MEMORY) {
trx->start_time = ut_time();
}
@@ -1536,6 +1536,7 @@ trx_commit_or_rollback_prepare(
/* fall through */
case TRX_STATE_ACTIVE:
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
/* If the trx is in a lock wait state, moves the waiting
query thread to the suspended state */
@@ -1661,6 +1662,7 @@ trx_commit_for_mysql(
/* fall through */
case TRX_STATE_ACTIVE:
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
trx->op_info = "committing";
trx_commit(trx);
MONITOR_DEC(MONITOR_TRX_ACTIVE);
@@ -1706,6 +1708,7 @@ trx_mark_sql_stat_end(
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
case TRX_STATE_NOT_STARTED:
@@ -1764,6 +1767,7 @@ trx_print_low(
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
@@ -1908,6 +1912,7 @@ wsrep_trx_print_locking(
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
@@ -2035,6 +2040,7 @@ trx_assert_started(
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
return(TRUE);
case TRX_STATE_ACTIVE:
@@ -2200,7 +2206,7 @@ trx_recover_for_mysql(
XID* xid_list, /*!< in/out: prepared transactions */
ulint len) /*!< in: number of slots in xid_list */
{
- const trx_t* trx;
+ trx_t* trx;
ulint count = 0;
ut_ad(xid_list);
@@ -2222,6 +2228,7 @@ trx_recover_for_mysql(
trx_sys->mutex. It may change to PREPARED, but not if
trx->is_recovered. It may also change to COMMITTED. */
if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+ trx->state = TRX_STATE_PREPARED_RECOVERED;
xid_list[count] = trx->xid;
if (count == 0) {
@@ -2246,11 +2253,22 @@ trx_recover_for_mysql(
count++;
if (count == len) {
- break;
+ goto partial;
}
}
}
+ /* After returning the full list, reset the state, because
+ there will be a second call to recover the transactions. */
+ for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
+ trx != NULL;
+ trx = UT_LIST_GET_NEXT(trx_list, trx)) {
+ if (trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) {
+ trx->state = TRX_STATE_PREPARED;
+ }
+ }
+
+partial:
mutex_exit(&trx_sys->mutex);
if (count > 0){
@@ -2293,7 +2311,8 @@ trx_get_trx_by_xid_low(
the same */
if (trx->is_recovered
- && trx_state_eq(trx, TRX_STATE_PREPARED)
+ && (trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED))
&& !trx->xid.is_null()
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
@@ -2373,6 +2392,7 @@ trx_start_if_not_started_xa_low(
case TRX_STATE_ACTIVE:
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}
@@ -2395,6 +2415,7 @@ trx_start_if_not_started_low(
case TRX_STATE_ACTIVE:
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}
@@ -2436,6 +2457,7 @@ trx_start_for_ddl_low(
ut_ad(trx->will_lock > 0);
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index b587aec5370..344f58decd0 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -4454,11 +4454,19 @@ dict_create_foreign_constraints_low(
}
orig = ptr;
- ptr = dict_accept(cs, ptr, "TABLE", &success);
-
- if (!success) {
-
- goto loop;
+ for (;;) {
+ ptr = dict_accept(cs, ptr, "TABLE", &success);
+ if (success) {
+ break;
+ }
+ ptr = dict_accept(cs, ptr, "ONLINE", &success);
+ if (success) {
+ continue;
+ }
+ ptr = dict_accept(cs, ptr, "IGNORE", &success);
+ if (!success) {
+ goto loop;
+ }
}
/* We are doing an ALTER TABLE: scan the table name we are altering */
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 77afde4c35c..b3a513b9b91 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -575,7 +575,7 @@ non-locking select */
ut_ad(!trx_is_autocommit_non_locking((t))); \
switch ((t)->state) { \
case TRX_STATE_PREPARED: \
- /* fall through */ \
+ case TRX_STATE_PREPARED_RECOVERED: \
case TRX_STATE_ACTIVE: \
case TRX_STATE_COMMITTED_IN_MEMORY: \
continue; \
@@ -768,6 +768,7 @@ struct trx_t{
TRX_STATE_NOT_STARTED
TRX_STATE_ACTIVE
TRX_STATE_PREPARED
+ TRX_STATE_PREPARED_RECOVERED (special case of TRX_STATE_PREPARED)
TRX_STATE_COMMITTED_IN_MEMORY (alias below COMMITTED)
Valid state transitions are:
diff --git a/storage/xtradb/include/trx0trx.ic b/storage/xtradb/include/trx0trx.ic
index eb7d62d9cad..6b8078a55e8 100644
--- a/storage/xtradb/include/trx0trx.ic
+++ b/storage/xtradb/include/trx0trx.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -49,6 +49,7 @@ trx_state_eq(
#ifdef UNIV_DEBUG
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
return(trx->state == state);
diff --git a/storage/xtradb/include/trx0types.h b/storage/xtradb/include/trx0types.h
index 7ca95131328..a0b398fffa1 100644
--- a/storage/xtradb/include/trx0types.h
+++ b/storage/xtradb/include/trx0types.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -48,7 +49,11 @@ enum trx_que_t {
enum trx_state_t {
TRX_STATE_NOT_STARTED,
TRX_STATE_ACTIVE,
- TRX_STATE_PREPARED, /* Support for 2PC/XA */
+ /** XA PREPARE has been executed; only XA COMMIT or XA ROLLBACK
+ are possible */
+ TRX_STATE_PREPARED,
+ /** XA PREPARE transaction that was returned to ha_recover() */
+ TRX_STATE_PREPARED_RECOVERED,
TRX_STATE_COMMITTED_IN_MEMORY
};
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index 9daa2cc906f..9c86abf7172 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2018, MariaDB Corporation.
+Copyright (c) 2014, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -8010,7 +8010,8 @@ lock_trx_release_locks(
{
assert_trx_in_list(trx);
- if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+ if (trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) {
mutex_enter(&trx_sys->mutex);
ut_a(trx_sys->n_prepared_trx > 0);
trx_sys->n_prepared_trx--;
diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc
index 56b7120fa34..6f393511611 100644
--- a/storage/xtradb/trx/trx0roll.cc
+++ b/storage/xtradb/trx/trx0roll.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2018, MariaDB Corporation.
+Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -208,6 +208,7 @@ trx_rollback_for_mysql(
return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx));
return(trx_rollback_for_mysql_low(trx));
@@ -260,6 +261,7 @@ trx_rollback_last_sql_stat_for_mysql(
return(err);
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
/* The statement rollback is only allowed on an ACTIVE
transaction, not a PREPARED or COMMITTED one. */
@@ -433,6 +435,7 @@ trx_rollback_to_savepoint_for_mysql(
return(trx_rollback_to_savepoint_for_mysql_low(
trx, savep, mysql_binlog_cache_pos));
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
/* The savepoint rollback is only allowed on an ACTIVE
transaction, not a PREPARED or COMMITTED one. */
@@ -722,6 +725,7 @@ fake_prepared:
}
return(FALSE);
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
goto func_exit;
case TRX_STATE_NOT_STARTED:
break;
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 17cba81daf3..1044a9321a0 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2018, MariaDB Corporation.
+Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -480,6 +480,7 @@ trx_free_prepared(
trx_t* trx) /*!< in, own: trx object */
{
ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)
|| (trx->is_recovered
&& (trx_state_eq(trx, TRX_STATE_ACTIVE)
|| trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY))
@@ -747,8 +748,7 @@ trx_resurrect_insert(
/* trx_start_low() is not called with resurrect, so need to initialize
start time here.*/
- if (trx->state == TRX_STATE_ACTIVE
- || trx->state == TRX_STATE_PREPARED) {
+ if (trx->state != TRX_STATE_COMMITTED_IN_MEMORY) {
trx->start_time = ut_time();
}
@@ -1790,6 +1790,7 @@ trx_commit_or_rollback_prepare(
/* fall through */
case TRX_STATE_ACTIVE:
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
/* If the trx is in a lock wait state, moves the waiting
query thread to the suspended state */
@@ -1927,6 +1928,7 @@ trx_commit_for_mysql(
/* fall through */
case TRX_STATE_ACTIVE:
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
trx->op_info = "committing";
trx_commit(trx);
MONITOR_DEC(MONITOR_TRX_ACTIVE);
@@ -1983,6 +1985,7 @@ trx_mark_sql_stat_end(
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
case TRX_STATE_NOT_STARTED:
@@ -2041,6 +2044,7 @@ trx_print_low(
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
@@ -2185,6 +2189,7 @@ wsrep_trx_print_locking(
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
(ulong) difftime(time(NULL), trx->start_time));
goto state_ok;
@@ -2313,6 +2318,7 @@ trx_assert_started(
switch (trx->state) {
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
return(TRUE);
case TRX_STATE_ACTIVE:
@@ -2478,7 +2484,7 @@ trx_recover_for_mysql(
XID* xid_list, /*!< in/out: prepared transactions */
ulint len) /*!< in: number of slots in xid_list */
{
- const trx_t* trx;
+ trx_t* trx;
ulint count = 0;
ut_ad(xid_list);
@@ -2500,6 +2506,7 @@ trx_recover_for_mysql(
trx_sys->mutex. It may change to PREPARED, but not if
trx->is_recovered. It may also change to COMMITTED. */
if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+ trx->state = TRX_STATE_PREPARED_RECOVERED;
xid_list[count] = trx->xid;
if (count == 0) {
@@ -2524,11 +2531,22 @@ trx_recover_for_mysql(
count++;
if (count == len) {
- break;
+ goto partial;
}
}
}
+ /* After returning the full list, reset the state, because
+ there will be a second call to recover the transactions. */
+ for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
+ trx != NULL;
+ trx = UT_LIST_GET_NEXT(trx_list, trx)) {
+ if (trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED)) {
+ trx->state = TRX_STATE_PREPARED;
+ }
+ }
+
+partial:
mutex_exit(&trx_sys->mutex);
if (count > 0){
@@ -2571,7 +2589,8 @@ trx_get_trx_by_xid_low(
the same */
if (trx->is_recovered
- && trx_state_eq(trx, TRX_STATE_PREPARED)
+ && (trx_state_eq(trx, TRX_STATE_PREPARED)
+ || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED))
&& !trx->xid.is_null()
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
@@ -2651,6 +2670,7 @@ trx_start_if_not_started_xa_low(
case TRX_STATE_ACTIVE:
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}
@@ -2677,6 +2697,7 @@ trx_start_if_not_started_low(
case TRX_STATE_ACTIVE:
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}
@@ -2722,6 +2743,7 @@ trx_start_for_ddl_low(
ut_ad(trx->will_lock > 0);
return;
case TRX_STATE_PREPARED:
+ case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY:
break;
}