summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_base.h10
-rw-r--r--mysql-test/suite/innodb/r/alter_copy.result213
-rw-r--r--mysql-test/suite/innodb/r/rename_table_debug.result23
-rw-r--r--mysql-test/suite/innodb/t/alter_copy.test91
-rw-r--r--mysql-test/suite/innodb/t/rename_table_debug.test33
-rw-r--r--mysql-test/suite/versioning/r/trx_id.result4
-rw-r--r--mysql-test/suite/versioning/t/trx_id.test4
-rw-r--r--sql/ha_partition.cc5
-rw-r--r--sql/sql_load.cc44
-rw-r--r--sql/sql_table.cc4
-rw-r--r--storage/innobase/fts/fts0fts.cc139
-rw-r--r--storage/innobase/handler/ha_innodb.cc173
-rw-r--r--storage/innobase/handler/ha_innodb.h3
-rw-r--r--storage/innobase/include/dict0mem.h7
-rw-r--r--storage/innobase/include/fts0fts.h22
-rw-r--r--storage/innobase/include/lock0lock.h24
-rw-r--r--storage/innobase/include/row0mysql.h18
-rw-r--r--storage/innobase/lock/lock0lock.cc139
-rw-r--r--storage/innobase/row/row0ins.cc27
-rw-r--r--storage/innobase/row/row0mysql.cc48
-rw-r--r--storage/innobase/row/row0purge.cc2
-rw-r--r--storage/innobase/row/row0uins.cc1
-rw-r--r--storage/innobase/row/row0umod.cc2
-rw-r--r--storage/innobase/row/row0undo.cc2
-rw-r--r--storage/innobase/row/row0upd.cc16
-rw-r--r--storage/innobase/trx/trx0rec.cc2
-rw-r--r--storage/mroonga/ha_mroonga.cpp10
27 files changed, 651 insertions, 415 deletions
diff --git a/include/my_base.h b/include/my_base.h
index 2c93165c912..5472473efa7 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 1995, 2017, MariaDB Corporation.
+ Copyright (c) 1995, 2018, 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
@@ -208,7 +208,13 @@ enum ha_extra_function {
Used in ha_partition::handle_ordered_index_scan() to inform engine
that we are starting an ordered index scan. Needed by Spider
*/
- HA_EXTRA_STARTING_ORDERED_INDEX_SCAN
+ HA_EXTRA_STARTING_ORDERED_INDEX_SCAN,
+ /** Start writing rows during ALTER TABLE...ALGORITHM=COPY. */
+ HA_EXTRA_BEGIN_ALTER_COPY,
+ /** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */
+ HA_EXTRA_END_ALTER_COPY,
+ /** Fake the start of a statement after wsrep_load_data_splitting hack */
+ HA_EXTRA_FAKE_START_STMT
};
/* Compatible option, to be deleted in 6.0 */
diff --git a/mysql-test/suite/innodb/r/alter_copy.result b/mysql-test/suite/innodb/r/alter_copy.result
new file mode 100644
index 00000000000..286c5152ded
--- /dev/null
+++ b/mysql-test/suite/innodb/r/alter_copy.result
@@ -0,0 +1,213 @@
+#
+# MDEV-11415 AVOID INTERMEDIATE COMMIT WHILE DOING
+# ALTER TABLE...ALGORITHM=COPY
+#
+CREATE TABLE t(a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB;
+CREATE TABLE t1(a INT, b TEXT, c TEXT,
+FULLTEXT(b), FULLTEXT(c(3)), FULLTEXT(b,c)) ENGINE=InnoDB;
+BEGIN;
+COMMIT;
+SELECT COUNT(*) FROM t;
+COUNT(*)
+999
+UPDATE t SET b=a%7, c=a%11, d=a%13;
+INSERT INTO t1 VALUES(1, 'This is a first b column', 'This is a first c column');
+INSERT INTO t1 VALUES(2, 'This is a second b column', 'This is a second c column');
+INSERT INTO t1(a) VALUES(3);
+INSERT INTO t1 VALUES(4, 'This is a third b column', 'This is a third c column');
+DELETE FROM t1 WHERE a = 2;
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+a b c
+1 This is a first b column This is a first c column
+4 This is a third b column This is a third c column
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` text DEFAULT NULL,
+ `c` text DEFAULT NULL,
+ FULLTEXT KEY `b` (`b`),
+ FULLTEXT KEY `c` (`c`),
+ FULLTEXT KEY `b_2` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1 FORCE, ALGORITHM=COPY;
+SET DEBUG_DBUG='+d,crash_commit_before';
+ALTER TABLE t ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c),
+ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c),
+ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b),
+ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a),
+ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b),
+ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a),
+ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c),
+ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c),
+ALGORITHM=COPY;
+ERROR HY000: Lost connection to MySQL server during query
+#sql-temporary.frm
+#sql-temporary.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTSBEING_DELETED.ibd
+FTSBEING_DELETED_CACHE.ibd
+FTSCONFIG.ibd
+FTSDELETED.ibd
+FTSDELETED_CACHE.ibd
+t.frm
+t.ibd
+t1.frm
+t1.ibd
+SHOW CREATE TABLE t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `b` int(11) DEFAULT NULL,
+ `c` int(11) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ UNIQUE KEY `a` (`a`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=latin1
+SELECT COUNT(*) FROM t;
+COUNT(*)
+999
+CHECK TABLE t;
+Table Op Msg_type Msg_text
+test.t check status OK
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+a b c
+1 This is a first b column This is a first c column
+4 This is a third b column This is a third c column
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` text DEFAULT NULL,
+ `c` text DEFAULT NULL,
+ FULLTEXT KEY `b` (`b`),
+ FULLTEXT KEY `c` (`c`),
+ FULLTEXT KEY `b_2` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+#sql-temporary.frm
+#sql-temporary.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTSBEING_DELETED.ibd
+FTSBEING_DELETED_CACHE.ibd
+FTSCONFIG.ibd
+FTSDELETED.ibd
+FTSDELETED_CACHE.ibd
+t.frm
+t.ibd
+t1.frm
+t1.ibd
+SHOW CREATE TABLE t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `b` int(11) DEFAULT NULL,
+ `c` int(11) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ UNIQUE KEY `a` (`a`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=latin1
+SELECT COUNT(*) FROM t;
+COUNT(*)
+999
+CHECK TABLE t;
+Table Op Msg_type Msg_text
+test.t check status OK
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+a b c
+1 This is a first b column This is a first c column
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+a b c
+1 This is a first b column This is a first c column
+4 This is a third b column This is a third c column
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` text DEFAULT NULL,
+ `c` text DEFAULT NULL,
+ FULLTEXT KEY `b` (`b`),
+ FULLTEXT KEY `c` (`c`),
+ FULLTEXT KEY `b_2` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+#sql-temporary.frm
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTS_INDEX_1.ibd
+FTS_INDEX_2.ibd
+FTS_INDEX_3.ibd
+FTS_INDEX_4.ibd
+FTS_INDEX_5.ibd
+FTS_INDEX_6.ibd
+FTSBEING_DELETED.ibd
+FTSBEING_DELETED_CACHE.ibd
+FTSCONFIG.ibd
+FTSDELETED.ibd
+FTSDELETED_CACHE.ibd
+t.frm
+t.ibd
+t1.frm
+t1.ibd
+DROP TABLE t1,t;
diff --git a/mysql-test/suite/innodb/r/rename_table_debug.result b/mysql-test/suite/innodb/r/rename_table_debug.result
index 7c9b961dee5..976b609bdd5 100644
--- a/mysql-test/suite/innodb/r/rename_table_debug.result
+++ b/mysql-test/suite/innodb/r/rename_table_debug.result
@@ -9,27 +9,4 @@ disconnect con1;
SELECT * FROM t1;
a b c d
1 NULL NULL NULL
-BEGIN;
-COMMIT;
-UPDATE t1 SET b=a%7, c=a%11, d=a%13;
-SET DEBUG_DBUG='+d,crash_commit_before';
-ALTER TABLE t1
-ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c),
-ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c),
-ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b),
-ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a),
-ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b),
-ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a),
-ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c),
-ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c),
-ALGORITHM=COPY;
-ERROR HY000: Lost connection to MySQL server during query
-CHECK TABLE t1;
-Table Op Msg_type Msg_text
-test.t1 check status OK
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-1000
DROP TABLE t1;
-SET GLOBAL innodb_background_drop_list_empty=
-@@GLOBAL.innodb_background_drop_list_empty;
diff --git a/mysql-test/suite/innodb/t/alter_copy.test b/mysql-test/suite/innodb/t/alter_copy.test
new file mode 100644
index 00000000000..0dce61994b5
--- /dev/null
+++ b/mysql-test/suite/innodb/t/alter_copy.test
@@ -0,0 +1,91 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/not_embedded.inc
+
+--echo #
+--echo # MDEV-11415 AVOID INTERMEDIATE COMMIT WHILE DOING
+--echo # ALTER TABLE...ALGORITHM=COPY
+--echo #
+
+CREATE TABLE t(a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB;
+CREATE TABLE t1(a INT, b TEXT, c TEXT,
+ FULLTEXT(b), FULLTEXT(c(3)), FULLTEXT(b,c)) ENGINE=InnoDB;
+
+let $c = 999;
+BEGIN;
+--disable_query_log
+while ($c) {
+INSERT INTO t() VALUES();
+dec $c;
+}
+--enable_query_log
+COMMIT;
+
+SELECT COUNT(*) FROM t;
+# try to make the to-be-created secondary index keys randomly distributed
+UPDATE t SET b=a%7, c=a%11, d=a%13;
+
+INSERT INTO t1 VALUES(1, 'This is a first b column', 'This is a first c column');
+INSERT INTO t1 VALUES(2, 'This is a second b column', 'This is a second c column');
+INSERT INTO t1(a) VALUES(3);
+INSERT INTO t1 VALUES(4, 'This is a third b column', 'This is a third c column');
+DELETE FROM t1 WHERE a = 2;
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+SHOW CREATE TABLE t1;
+ALTER TABLE t1 FORCE, ALGORITHM=COPY;
+
+# crash right after the last write_row(), before the first commit of ALTER TABLE
+--source include/expect_crash.inc
+
+SET DEBUG_DBUG='+d,crash_commit_before';
+--error 2013
+# create 32 secondary indexes
+ALTER TABLE t ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c),
+ ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c),
+ ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b),
+ ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a),
+ ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b),
+ ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a),
+ ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c),
+ ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c),
+ ALGORITHM=COPY;
+
+--let $restart_parameters= --innodb-force-recovery=3
+--source include/start_mysqld.inc
+let $datadir=`select @@datadir`;
+--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
+--list_files $datadir/test
+SHOW CREATE TABLE t;
+SELECT COUNT(*) FROM t;
+CHECK TABLE t;
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+SHOW CREATE TABLE t1;
+CHECK TABLE t1;
+
+--let $restart_parameters= --innodb-read-only
+--source include/restart_mysqld.inc
+--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
+
+--list_files $datadir/test
+SHOW CREATE TABLE t;
+SELECT COUNT(*) FROM t;
+CHECK TABLE t;
+SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
+SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
+SHOW CREATE TABLE t1;
+CHECK TABLE t1;
+
+--let $restart_parameters=
+--source include/restart_mysqld.inc
+--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
+--list_files $datadir/test
+DROP TABLE t1,t;
+
+# Work around missing crash recovery at the SQL layer.
+--remove_files_wildcard $datadir/test #sql-*.frm
diff --git a/mysql-test/suite/innodb/t/rename_table_debug.test b/mysql-test/suite/innodb/t/rename_table_debug.test
index 20af12dc15c..df4331cf8bb 100644
--- a/mysql-test/suite/innodb/t/rename_table_debug.test
+++ b/mysql-test/suite/innodb/t/rename_table_debug.test
@@ -18,37 +18,4 @@ SET DEBUG_SYNC='now WAIT_FOR renamed';
--source include/restart_mysqld.inc
--disconnect con1
SELECT * FROM t1;
-
-let $c = 999;
-BEGIN;
---disable_query_log
-while ($c) {
-INSERT INTO t1() VALUES();
-dec $c;
-}
---enable_query_log
-COMMIT;
-UPDATE t1 SET b=a%7, c=a%11, d=a%13;
-
---source include/expect_crash.inc
-SET DEBUG_DBUG='+d,crash_commit_before';
---error 2013
-ALTER TABLE t1
-ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c),
-ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c),
-ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b),
-ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a),
-ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b),
-ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a),
-ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c),
-ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c),
-ALGORITHM=COPY;
---source include/start_mysqld.inc
-CHECK TABLE t1;
-SELECT COUNT(*) FROM t1;
DROP TABLE t1;
-# MDEV-11415 TODO: remove the following
-SET GLOBAL innodb_background_drop_list_empty=
-@@GLOBAL.innodb_background_drop_list_empty;
-# Work around missing crash recovery at the SQL layer.
---remove_files_wildcard $datadir/test #sql-*.frm
diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result
index a88ba7eec2b..940a6479934 100644
--- a/mysql-test/suite/versioning/r/trx_id.result
+++ b/mysql-test/suite/versioning/r/trx_id.result
@@ -53,8 +53,8 @@ add column e bigint unsigned as row end,
add period for system_time(s, e),
add system versioning,
algorithm=copy;
-select check_result(count(*) = @tmp) from mysql.transaction_registry;
-check_result(count(*) = @tmp)
+select check_result(count(*) = @tmp + 1) from mysql.transaction_registry;
+check_result(count(*) = @tmp + 1)
[CORRECT]
# TRX_ID to TIMESTAMP versioning switch
create or replace table t1 (
diff --git a/mysql-test/suite/versioning/t/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test
index ee4e927b506..933f0618577 100644
--- a/mysql-test/suite/versioning/t/trx_id.test
+++ b/mysql-test/suite/versioning/t/trx_id.test
@@ -57,8 +57,8 @@ alter table t1
add period for system_time(s, e),
add system versioning,
algorithm=copy;
-select check_result(count(*) = @tmp) from mysql.transaction_registry;
-
+# With MDEV-14511 the transaction will be registered even for empty tables.
+select check_result(count(*) = @tmp + 1) from mysql.transaction_registry;
--echo # TRX_ID to TIMESTAMP versioning switch
create or replace table t1 (
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 8675aed3228..87c056e7bae 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2005, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+ Copyright (c) 2009, 2018, MariaDB
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
@@ -8897,6 +8897,9 @@ int ha_partition::extra(enum ha_extra_function operation)
*/
DBUG_RETURN(ER_UNSUPORTED_LOG_ENGINE);
case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
+ case HA_EXTRA_BEGIN_ALTER_COPY:
+ case HA_EXTRA_END_ALTER_COPY:
+ case HA_EXTRA_FAKE_START_STMT:
DBUG_RETURN(loop_extra(operation));
default:
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 9a15d4b9c0d..93669554a5a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB Corporation
+ Copyright (c) 2010, 2018, 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
@@ -97,6 +97,45 @@ public:
#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
#define PUSH(A) *(stack_pos++)=(A)
+#ifdef WITH_WSREP
+/** If requested by wsrep_load_data_splitting, commit and restart
+the transaction after every 10,000 inserted rows. */
+
+static bool wsrep_load_data_split(THD *thd, const TABLE *table,
+ const COPY_INFO &info)
+{
+ extern struct handlerton* innodb_hton_ptr;
+
+ DBUG_ENTER("wsrep_load_data_split");
+
+ if (wsrep_load_data_splitting && wsrep_on(thd)
+ && info.records && !(info.records % 10000)
+ && thd->transaction.stmt.ha_list
+ && thd->transaction.stmt.ha_list->ht() == binlog_hton
+ && thd->transaction.stmt.ha_list->next()
+ && thd->transaction.stmt.ha_list->next()->ht() == innodb_hton_ptr
+ && !thd->transaction.stmt.ha_list->next()->next())
+ {
+ WSREP_DEBUG("intermediate transaction commit in LOAD DATA");
+ if (wsrep_run_wsrep_commit(thd, true) != WSREP_TRX_OK) DBUG_RETURN(true);
+ if (binlog_hton->commit(binlog_hton, thd, true)) DBUG_RETURN(true);
+ wsrep_post_commit(thd, true);
+ innodb_hton_ptr->commit(innodb_hton_ptr, thd, true);
+ table->file->extra(HA_EXTRA_FAKE_START_STMT);
+ }
+
+ DBUG_RETURN(false);
+}
+# define WSREP_LOAD_DATA_SPLIT(thd,table,info) \
+ if (wsrep_load_data_split(thd,table,info)) \
+ { \
+ table->auto_increment_field_not_null= FALSE; \
+ DBUG_RETURN(1); \
+ }
+#else /* WITH_WSREP */
+#define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */
+#endif /* WITH_WSREP */
+
class READ_INFO {
File file;
String data; /* Read buffer */
@@ -989,6 +1028,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(-1);
}
+ WSREP_LOAD_DATA_SPLIT(thd, table, info);
err= write_record(thd, table, &info);
table->auto_increment_field_not_null= FALSE;
if (err)
@@ -1194,6 +1234,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(-1);
}
+ WSREP_LOAD_DATA_SPLIT(thd, table, info);
err= write_record(thd, table, &info);
table->auto_increment_field_not_null= FALSE;
if (err)
@@ -1348,6 +1389,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(-1);
}
+ WSREP_LOAD_DATA_SPLIT(thd, table, info);
err= write_record(thd, table, &info);
table->auto_increment_field_not_null= false;
if (err)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7974718e8dd..dc0accad799 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -10357,6 +10357,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
thd->progress.max_counter= from->file->records();
time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10;
+ if (!ignore) /* for now, InnoDB needs the undo log for ALTER IGNORE */
+ to->file->extra(HA_EXTRA_BEGIN_ALTER_COPY);
while (!(error= info.read_record()))
{
@@ -10516,6 +10518,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->print_error(my_errno,MYF(0));
error= 1;
}
+ if (!ignore)
+ to->file->extra(HA_EXTRA_END_ALTER_COPY);
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (mysql_trans_commit_alter_copy_data(thd))
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 403f1d57b9d..59488d15750 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -2309,7 +2309,6 @@ fts_savepoint_create(
/******************************************************************//**
Create an FTS trx.
@return FTS trx */
-static
fts_trx_t*
fts_trx_create(
/*===========*/
@@ -3340,6 +3339,144 @@ fts_fetch_doc_from_rec(
}
}
+/** Fetch the data from tuple and tokenize the document.
+@param[in] get_doc FTS index's get_doc struct
+@param[in] tuple tuple should be arranged in table schema order
+@param[out] doc fts doc to hold parsed documents. */
+static
+void
+fts_fetch_doc_from_tuple(
+ fts_get_doc_t* get_doc,
+ const dtuple_t* tuple,
+ fts_doc_t* doc)
+{
+ dict_index_t* index;
+ st_mysql_ftparser* parser;
+ ulint doc_len = 0;
+ ulint processed_doc = 0;
+ ulint num_field;
+
+ if (get_doc == NULL) {
+ return;
+ }
+
+ index = get_doc->index_cache->index;
+ parser = get_doc->index_cache->index->parser;
+ num_field = dict_index_get_n_fields(index);
+
+ for (ulint i = 0; i < num_field; i++) {
+ const dict_field_t* ifield;
+ const dict_col_t* col;
+ ulint pos;
+ dfield_t* field;
+
+ ifield = dict_index_get_nth_field(index, i);
+ col = dict_field_get_col(ifield);
+ pos = dict_col_get_no(col);
+ field = dtuple_get_nth_field(tuple, pos);
+
+ if (!get_doc->index_cache->charset) {
+ get_doc->index_cache->charset = fts_get_charset(
+ ifield->col->prtype);
+ }
+
+ ut_ad(!dfield_is_ext(field));
+
+ doc->text.f_str = (byte*) dfield_get_data(field);
+ doc->text.f_len = dfield_get_len(field);
+ doc->found = TRUE;
+ doc->charset = get_doc->index_cache->charset;
+
+ /* field data is NULL. */
+ if (doc->text.f_len == UNIV_SQL_NULL || doc->text.f_len == 0) {
+ continue;
+ }
+
+ if (processed_doc == 0) {
+ fts_tokenize_document(doc, NULL, parser);
+ } else {
+ fts_tokenize_document_next(doc, doc_len, NULL, parser);
+ }
+
+ processed_doc++;
+ doc_len += doc->text.f_len + 1;
+ }
+}
+
+/** Fetch the document from tuple, tokenize the text data and
+insert the text data into fts auxiliary table and
+its cache. Moreover this tuple fields doesn't contain any information
+about externally stored field. This tuple contains data directly
+converted from mysql.
+@param[in] ftt FTS transaction table
+@param[in] doc_id doc id
+@param[in] tuple tuple from where data can be retrieved
+ and tuple should be arranged in table
+ schema order. */
+void
+fts_add_doc_from_tuple(
+ fts_trx_table_t*ftt,
+ doc_id_t doc_id,
+ const dtuple_t* tuple)
+{
+ mtr_t mtr;
+ fts_cache_t* cache = ftt->table->fts->cache;
+
+ ut_ad(cache->get_docs);
+
+ if (!(ftt->table->fts->fts_status & ADDED_TABLE_SYNCED)) {
+ fts_init_index(ftt->table, FALSE);
+ }
+
+ mtr_start(&mtr);
+
+ ulint num_idx = ib_vector_size(cache->get_docs);
+
+ for (ulint i = 0; i < num_idx; ++i) {
+ fts_doc_t doc;
+ dict_table_t* table;
+ fts_get_doc_t* get_doc;
+
+ get_doc = static_cast<fts_get_doc_t*>(
+ ib_vector_get(cache->get_docs, i));
+ table = get_doc->index_cache->index->table;
+
+ fts_doc_init(&doc);
+ fts_fetch_doc_from_tuple(
+ get_doc, tuple, &doc);
+
+ if (doc.found) {
+ mtr_commit(&mtr);
+ rw_lock_x_lock(&table->fts->cache->lock);
+
+ if (table->fts->cache->stopword_info.status
+ & STOPWORD_NOT_INIT) {
+ fts_load_stopword(table, NULL, NULL,
+ NULL, TRUE, TRUE);
+ }
+
+ fts_cache_add_doc(
+ table->fts->cache,
+ get_doc->index_cache,
+ doc_id, doc.tokens);
+
+ rw_lock_x_unlock(&table->fts->cache->lock);
+
+ if (cache->total_size > fts_max_cache_size / 5
+ || fts_need_sync) {
+ fts_sync(cache->sync, true, false, false);
+ }
+
+ mtr_start(&mtr);
+
+ }
+
+ fts_doc_free(&doc);
+ }
+
+ mtr_commit(&mtr);
+}
+
/*********************************************************************//**
This function fetches the document inserted during the committing
transaction, and tokenize the inserted text data and insert into
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 0479699f4f6..b190df6dded 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -185,7 +185,7 @@ static mysql_mutex_t pending_checkpoint_mutex;
#define EQ_CURRENT_THD(thd) ((thd) == current_thd)
-static struct handlerton* innodb_hton_ptr;
+struct handlerton* innodb_hton_ptr;
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
@@ -2996,7 +2996,6 @@ ha_innobase::ha_innobase(
| (srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0)
),
m_start_of_scan(),
- m_num_write_row(),
m_mysql_has_locked()
{}
@@ -8177,7 +8176,6 @@ ha_innobase::write_row(
#ifdef WITH_WSREP
ibool auto_inc_inserted= FALSE; /* if NULL was inserted */
#endif
- ulint sql_command;
int error_result = 0;
bool auto_inc_used = false;
@@ -8195,7 +8193,7 @@ ha_innobase::write_row(
DB_FORCED_ABORT, 0, m_user_thd));
}
- /* Step-1: Validation checks before we commence write_row operation. */
+ /* Validation checks before we commence write_row operation. */
if (high_level_read_only) {
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
@@ -8216,131 +8214,7 @@ ha_innobase::write_row(
++trx->will_lock;
}
- /* Step-2: Intermediate commit if original operation involves ALTER
- table with algorithm = copy. Intermediate commit ease pressure on
- recovery if server crashes while ALTER is active. */
- sql_command = thd_sql_command(m_user_thd);
-
- if ((sql_command == SQLCOM_ALTER_TABLE
- || sql_command == SQLCOM_OPTIMIZE
- || sql_command == SQLCOM_CREATE_INDEX
-#ifdef WITH_WSREP
- || (sql_command == SQLCOM_LOAD
- && wsrep_load_data_splitting && wsrep_on(m_user_thd)
- && !thd_test_options(
- m_user_thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
-#endif /* WITH_WSREP */
- || sql_command == SQLCOM_DROP_INDEX)
- && m_num_write_row >= 10000) {
-#ifdef WITH_WSREP
- if (sql_command == SQLCOM_LOAD && wsrep_on(m_user_thd)) {
- WSREP_DEBUG("forced trx split for LOAD: %s",
- wsrep_thd_query(m_user_thd));
- }
-#endif /* WITH_WSREP */
- /* ALTER TABLE is COMMITted at every 10000 copied rows.
- The IX table lock for the original table has to be re-issued.
- As this method will be called on a temporary table where the
- contents of the original table is being copied to, it is
- a bit tricky to determine the source table. The cursor
- position in the source table need not be adjusted after the
- intermediate COMMIT, since writes by other transactions are
- being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
-
- dict_table_t* src_table;
- enum lock_mode mode;
-
- m_num_write_row = 0;
-
- /* Commit the transaction. This will release the table
- locks, so they have to be acquired again. */
-
- /* Altering an InnoDB table */
- /* Get the source table. */
- src_table = lock_get_src_table(
- m_prebuilt->trx, m_prebuilt->table, &mode);
- if (!src_table) {
-no_commit:
- /* Unknown situation: do not commit */
- ;
- } else if (src_table == m_prebuilt->table) {
-#ifdef WITH_WSREP
- if (wsrep_on(m_user_thd) &&
- wsrep_load_data_splitting &&
- sql_command == SQLCOM_LOAD &&
- !thd_test_options(m_user_thd,
- OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
- {
- switch (wsrep_run_wsrep_commit(m_user_thd, 1)) {
- case WSREP_TRX_OK:
- break;
- case WSREP_TRX_SIZE_EXCEEDED:
- case WSREP_TRX_CERT_FAIL:
- case WSREP_TRX_ERROR:
- DBUG_RETURN(1);
- }
-
- if (binlog_hton->commit(binlog_hton, m_user_thd, 1)) {
- DBUG_RETURN(1);
- }
- wsrep_post_commit(m_user_thd, TRUE);
- }
-#endif /* WITH_WSREP */
- /* Source table is not in InnoDB format:
- no need to re-acquire locks on it. */
-
- /* Altering to InnoDB format */
- innobase_commit(ht, m_user_thd, 1);
- /* Note that this transaction is still active. */
- trx_register_for_2pc(m_prebuilt->trx);
- /* We will need an IX lock on the destination table. */
- m_prebuilt->sql_stat_start = TRUE;
- } else {
-#ifdef WITH_WSREP
- if (wsrep_on(m_user_thd) &&
- wsrep_load_data_splitting &&
- sql_command == SQLCOM_LOAD &&
- !thd_test_options(m_user_thd,
- OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
- switch (wsrep_run_wsrep_commit(m_user_thd, 1)) {
- case WSREP_TRX_OK:
- break;
- case WSREP_TRX_SIZE_EXCEEDED:
- case WSREP_TRX_CERT_FAIL:
- case WSREP_TRX_ERROR:
- DBUG_RETURN(1);
- }
-
- if (binlog_hton->commit(binlog_hton, m_user_thd, 1)) {
- DBUG_RETURN(1);
- }
-
- wsrep_post_commit(m_user_thd, TRUE);
- }
-#endif /* WITH_WSREP */
- /* Ensure that there are no other table locks than
- LOCK_IX and LOCK_AUTO_INC on the destination table. */
-
- if (!lock_is_table_exclusive(m_prebuilt->table,
- m_prebuilt->trx)) {
- goto no_commit;
- }
-
- /* Commit the transaction. This will release the table
- locks, so they have to be acquired again. */
- innobase_commit(ht, m_user_thd, 1);
- /* Note that this transaction is still active. */
- trx_register_for_2pc(m_prebuilt->trx);
- /* Re-acquire the table lock on the source table. */
- row_lock_table_for_mysql(m_prebuilt, src_table, mode);
- /* We will need an IX lock on the destination table. */
- m_prebuilt->sql_stat_start = TRUE;
- }
- }
-
- m_num_write_row++;
-
- /* Step-3: Handling of Auto-Increment Columns. */
+ /* Handling of Auto-Increment Columns. */
if (table->next_number_field && record == table->record[0]) {
/* Reset the error code before calling
@@ -8373,7 +8247,7 @@ no_commit:
auto_inc_used = true;
}
- /* Step-4: Prepare INSERT graph that will be executed for actual INSERT
+ /* Prepare INSERT graph that will be executed for actual INSERT
(This is a one time operation) */
if (m_prebuilt->mysql_template == NULL
|| m_prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
@@ -8389,12 +8263,12 @@ no_commit:
vers_set_fields = table->versioned_write(VERS_TRX_ID) ?
ROW_INS_VERSIONED : ROW_INS_NORMAL;
- /* Step-5: Execute insert graph that will result in actual insert. */
+ /* Execute insert graph that will result in actual insert. */
error = row_insert_for_mysql((byte*) record, m_prebuilt, vers_set_fields);
DEBUG_SYNC(m_user_thd, "ib_after_row_insert");
- /* Step-6: Handling of errors related to auto-increment. */
+ /* Handling of errors related to auto-increment. */
if (auto_inc_used) {
ulonglong auto_inc;
ulonglong col_max_value;
@@ -8422,13 +8296,11 @@ no_commit:
must update the autoinc counter if we are performing
those statements. */
- switch (sql_command) {
+ switch (thd_sql_command(m_user_thd)) {
case SQLCOM_LOAD:
- if (trx->duplicates) {
-
- goto set_max_autoinc;
+ if (!trx->duplicates) {
+ break;
}
- break;
case SQLCOM_REPLACE:
case SQLCOM_INSERT_SELECT:
@@ -8517,7 +8389,7 @@ set_max_autoinc:
innobase_srv_conc_exit_innodb(m_prebuilt);
report_error:
- /* Step-7: Cleanup and exit. */
+ /* Cleanup and exit. */
if (error == DB_TABLESPACE_DELETED) {
ib_senderrf(
trx->mysql_thd, IB_LOG_LEVEL_ERROR,
@@ -15752,6 +15624,26 @@ ha_innobase::extra(
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
break;
+ case HA_EXTRA_BEGIN_ALTER_COPY:
+ m_prebuilt->table->skip_alter_undo = 1;
+ if (m_prebuilt->table->is_temporary()
+ || !m_prebuilt->table->versioned_by_id()) {
+ break;
+ }
+ trx_start_if_not_started(m_prebuilt->trx, true);
+ m_prebuilt->trx->mod_tables.insert(
+ trx_mod_tables_t::value_type(
+ const_cast<dict_table_t*>(m_prebuilt->table),
+ 0))
+ .first->second.set_versioned(0);
+ break;
+ case HA_EXTRA_END_ALTER_COPY:
+ m_prebuilt->table->skip_alter_undo = 0;
+ break;
+ case HA_EXTRA_FAKE_START_STMT:
+ trx_register_for_2pc(m_prebuilt->trx);
+ m_prebuilt->sql_stat_start = true;
+ break;
default:/* Do nothing */
;
}
@@ -15854,7 +15746,7 @@ ha_innobase::start_stmt(
init_table_handle_for_HANDLER();
m_prebuilt->select_lock_type = LOCK_X;
m_prebuilt->stored_select_lock_type = LOCK_X;
- error = row_lock_table_for_mysql(m_prebuilt, NULL, 1);
+ error = row_lock_table(m_prebuilt);
if (error != DB_SUCCESS) {
int st = convert_error_code_to_mysql(
@@ -16118,8 +16010,7 @@ ha_innobase::external_lock(
&& thd_test_options(thd, OPTION_NOT_AUTOCOMMIT)
&& thd_in_lock_tables(thd)) {
- dberr_t error = row_lock_table_for_mysql(
- m_prebuilt, NULL, 0);
+ dberr_t error = row_lock_table(m_prebuilt);
if (error != DB_SUCCESS) {
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index d7f5d36a680..492e61be3fa 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -515,9 +515,6 @@ protected:
ROW_SEL_EXACT_PREFIX, or undefined */
uint m_last_match_mode;
- /** number of write_row() calls */
- uint m_num_write_row;
-
/** If mysql has locked with external_lock() */
bool m_mysql_has_locked;
};
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index e9b60debbc9..01840379a71 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1609,6 +1609,13 @@ struct dict_table_t {
Use DICT_TF2_FLAG_IS_SET() to parse this flag. */
unsigned flags2:DICT_TF2_BITS;
+ /** TRUE if the table is an intermediate table during copy alter
+ operation or a partition/subpartition which is required for copying
+ data and skip the undo log for insertion of row in the table.
+ This variable will be set and unset during extra(), or during the
+ process of altering partitions */
+ unsigned skip_alter_undo:1;
+
/*!< whether this is in a single-table tablespace and the .ibd
file is missing or page decryption failed and page is corrupted */
unsigned file_unreadable:1;
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index 813e34b43d3..362bdcb7fe6 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -1015,5 +1015,27 @@ fts_check_corrupt(
dict_table_t* base_table,
trx_t* trx);
+/** Fetch the document from tuple, tokenize the text data and
+insert the text data into fts auxiliary table and
+its cache. Moreover this tuple fields doesn't contain any information
+about externally stored field. This tuple contains data directly
+converted from mysql.
+@param[in] ftt FTS transaction table
+@param[in] doc_id doc id
+@param[in] tuple tuple from where data can be retrieved
+ and tuple should be arranged in table
+ schema order. */
+void
+fts_add_doc_from_tuple(
+ fts_trx_table_t*ftt,
+ doc_id_t doc_id,
+ const dtuple_t* tuple);
+
+/** Create an FTS trx.
+@param[in,out] trx InnoDB Transaction
+@return FTS transaction. */
+fts_trx_t*
+fts_trx_create(
+ trx_t* trx);
#endif /*!< fts0fts.h */
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 658211b4aca..1ef2f12975a 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -554,30 +554,6 @@ lock_rec_find_set_bit(
bit set */
/*********************************************************************//**
-Gets the source table of an ALTER TABLE transaction. The table must be
-covered by an IX or IS table lock.
-@return the source table of transaction, if it is covered by an IX or
-IS table lock; dest if there is no source table, and NULL if the
-transaction is locking more than two tables or an inconsistency is
-found */
-dict_table_t*
-lock_get_src_table(
-/*===============*/
- trx_t* trx, /*!< in: transaction */
- dict_table_t* dest, /*!< in: destination of ALTER TABLE */
- lock_mode* mode); /*!< out: lock mode of the source table */
-/*********************************************************************//**
-Determine if the given table is exclusively "owned" by the given
-transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
-on the table.
-@return TRUE if table is only locked by trx, with LOCK_IX, and
-possibly LOCK_AUTO_INC */
-ibool
-lock_is_table_exclusive(
-/*====================*/
- const dict_table_t* table, /*!< in: table */
- const trx_t* trx); /*!< in: transaction */
-/*********************************************************************//**
Checks if a lock request lock1 has to wait for request lock2.
@return TRUE if lock1 has to wait for lock2 to be removed */
ibool
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 407e1705a0f..77b8337ac91 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2017, 2018, 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
@@ -219,21 +219,11 @@ row_lock_table_autoinc_for_mysql(
table handle */
MY_ATTRIBUTE((nonnull, warn_unused_result));
-/*********************************************************************//**
-Sets a table lock on the table mentioned in prebuilt.
+/** Lock a table.
+@param[in,out] prebuilt table handle
@return error code or DB_SUCCESS */
dberr_t
-row_lock_table_for_mysql(
-/*=====================*/
- row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
- table handle */
- dict_table_t* table, /*!< in: table to lock, or NULL
- if prebuilt->table should be
- locked as
- prebuilt->select_lock_type */
- ulint mode) /*!< in: lock mode of table
- (ignored if table==NULL) */
- MY_ATTRIBUTE((nonnull(1)));
+row_lock_table(row_prebuilt_t* prebuilt);
/** System Versioning: row_insert_for_mysql() modes */
enum ins_mode_t {
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 9d7f6d61fc4..792fb8ffc8b 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -618,145 +618,6 @@ lock_get_size(void)
}
/*********************************************************************//**
-Gets the source table of an ALTER TABLE transaction. The table must be
-covered by an IX or IS table lock.
-@return the source table of transaction, if it is covered by an IX or
-IS table lock; dest if there is no source table, and NULL if the
-transaction is locking more than two tables or an inconsistency is
-found */
-dict_table_t*
-lock_get_src_table(
-/*===============*/
- trx_t* trx, /*!< in: transaction */
- dict_table_t* dest, /*!< in: destination of ALTER TABLE */
- lock_mode* mode) /*!< out: lock mode of the source table */
-{
- dict_table_t* src;
- lock_t* lock;
-
- ut_ad(!lock_mutex_own());
-
- src = NULL;
- *mode = LOCK_NONE;
-
- /* The trx mutex protects the trx_locks for our purposes.
- Other transactions could want to convert one of our implicit
- record locks to an explicit one. For that, they would need our
- trx mutex. Waiting locks can be removed while only holding
- lock_sys->mutex, but this is a running transaction and cannot
- thus be holding any waiting locks. */
- trx_mutex_enter(trx);
-
- for (lock = UT_LIST_GET_FIRST(trx->lock.trx_locks);
- lock != NULL;
- lock = UT_LIST_GET_NEXT(trx_locks, lock)) {
- lock_table_t* tab_lock;
- lock_mode lock_mode;
- if (!(lock_get_type_low(lock) & LOCK_TABLE)) {
- /* We are only interested in table locks. */
- continue;
- }
- tab_lock = &lock->un_member.tab_lock;
- if (dest == tab_lock->table) {
- /* We are not interested in the destination table. */
- continue;
- } else if (!src) {
- /* This presumably is the source table. */
- src = tab_lock->table;
- if (UT_LIST_GET_LEN(src->locks) != 1
- || UT_LIST_GET_FIRST(src->locks) != lock) {
- /* We only support the case when
- there is only one lock on this table. */
- src = NULL;
- goto func_exit;
- }
- } else if (src != tab_lock->table) {
- /* The transaction is locking more than
- two tables (src and dest): abort */
- src = NULL;
- goto func_exit;
- }
-
- /* Check that the source table is locked by
- LOCK_IX or LOCK_IS. */
- lock_mode = lock_get_mode(lock);
- if (lock_mode == LOCK_IX || lock_mode == LOCK_IS) {
- if (*mode != LOCK_NONE && *mode != lock_mode) {
- /* There are multiple locks on src. */
- src = NULL;
- goto func_exit;
- }
- *mode = lock_mode;
- }
- }
-
- if (!src) {
- /* No source table lock found: flag the situation to caller */
- src = dest;
- }
-
-func_exit:
- trx_mutex_exit(trx);
- return(src);
-}
-
-/*********************************************************************//**
-Determine if the given table is exclusively "owned" by the given
-transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
-on the table.
-@return TRUE if table is only locked by trx, with LOCK_IX, and
-possibly LOCK_AUTO_INC */
-ibool
-lock_is_table_exclusive(
-/*====================*/
- const dict_table_t* table, /*!< in: table */
- const trx_t* trx) /*!< in: transaction */
-{
- const lock_t* lock;
- ibool ok = FALSE;
-
- ut_ad(table);
- ut_ad(trx);
-
- lock_mutex_enter();
-
- for (lock = UT_LIST_GET_FIRST(table->locks);
- lock != NULL;
- lock = UT_LIST_GET_NEXT(locks, &lock->un_member.tab_lock)) {
- if (lock->trx != trx) {
- /* A lock on the table is held
- by some other transaction. */
- goto not_ok;
- }
-
- if (!(lock_get_type_low(lock) & LOCK_TABLE)) {
- /* We are interested in table locks only. */
- continue;
- }
-
- switch (lock_get_mode(lock)) {
- case LOCK_IX:
- ok = TRUE;
- break;
- case LOCK_AUTO_INC:
- /* It is allowed for trx to hold an
- auto_increment lock. */
- break;
- default:
-not_ok:
- /* Other table locks than LOCK_IX are not allowed. */
- ok = FALSE;
- goto func_exit;
- }
- }
-
-func_exit:
- lock_mutex_exit();
-
- return(ok);
-}
-
-/*********************************************************************//**
Sets the wait flag of a lock and the back pointer in trx to lock. */
UNIV_INLINE
void
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 5ed664ee0ee..027d159f4e4 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -3230,7 +3230,7 @@ row_ins_clust_index_entry(
n_uniq = dict_index_is_unique(index) ? index->n_uniq : 0;
- const ulint flags = index->table->no_rollback() ? BTR_NO_ROLLBACK
+ ulint flags = index->table->no_rollback() ? BTR_NO_ROLLBACK
: dict_table_is_temporary(index->table)
? BTR_NO_LOCKING_FLAG : 0;
const ulint orig_n_fields = entry->n_fields;
@@ -3238,6 +3238,17 @@ row_ins_clust_index_entry(
/* Try first optimistic descent to the B-tree */
log_free_check();
+ /* For intermediate table during copy alter table,
+ skip the undo log and record lock checking for
+ insertion operation.
+ */
+ if (index->table->skip_alter_undo) {
+ flags |= BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG;
+ }
+
+ /* Try first optimistic descent to the B-tree */
+ log_free_check();
+
err = row_ins_clust_index_entry_low(
flags, BTR_MODIFY_LEAF, index, n_uniq, entry,
n_ext, thr, dup_chk_only);
@@ -3283,6 +3294,7 @@ row_ins_sec_index_entry(
dberr_t err;
mem_heap_t* offsets_heap;
mem_heap_t* heap;
+ trx_id_t trx_id = 0;
DBUG_EXECUTE_IF("row_ins_sec_index_entry_timeout", {
DBUG_SET("-d,row_ins_sec_index_entry_timeout");
@@ -3305,13 +3317,22 @@ row_ins_sec_index_entry(
/* Try first optimistic descent to the B-tree */
log_free_check();
- const ulint flags = dict_table_is_temporary(index->table)
+ ulint flags = dict_table_is_temporary(index->table)
? BTR_NO_LOCKING_FLAG
: 0;
+ /* For intermediate table during copy alter table,
+ skip the undo log and record lock checking for
+ insertion operation.
+ */
+ if (index->table->skip_alter_undo) {
+ trx_id = thr_get_trx(thr)->id;
+ flags |= BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG;
+ }
+
err = row_ins_sec_index_entry_low(
flags, BTR_MODIFY_LEAF, index, offsets_heap, heap, entry,
- 0, thr, dup_chk_only);
+ trx_id, thr, dup_chk_only);
if (err == DB_FAIL) {
mem_heap_empty(heap);
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 2418e8de433..6605fd681ed 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1266,20 +1266,11 @@ run_again:
return(err);
}
-/*********************************************************************//**
-Sets a table lock on the table mentioned in prebuilt.
+/** Lock a table.
+@param[in,out] prebuilt table handle
@return error code or DB_SUCCESS */
dberr_t
-row_lock_table_for_mysql(
-/*=====================*/
- row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
- table handle */
- dict_table_t* table, /*!< in: table to lock, or NULL
- if prebuilt->table should be
- locked as
- prebuilt->select_lock_type */
- ulint mode) /*!< in: lock mode of table
- (ignored if table==NULL) */
+row_lock_table(row_prebuilt_t* prebuilt)
{
trx_t* trx = prebuilt->trx;
que_thr_t* thr;
@@ -1309,17 +1300,10 @@ run_again:
trx_start_if_not_started_xa(trx, false);
- if (table) {
- err = lock_table(
- 0, table,
- static_cast<enum lock_mode>(mode), thr);
- } else {
- err = lock_table(
- 0, prebuilt->table,
- static_cast<enum lock_mode>(
- prebuilt->select_lock_type),
- thr);
- }
+ err = lock_table(0, prebuilt->table,
+ static_cast<enum lock_mode>(
+ prebuilt->select_lock_type),
+ thr);
trx->error_state = err;
@@ -1599,9 +1583,21 @@ error_exit:
}
}
- /* Pass NULL for the columns affected, since an INSERT affects
- all FTS indexes. */
- fts_trx_add_op(trx, table, doc_id, FTS_INSERT, NULL);
+ if (table->skip_alter_undo) {
+ if (trx->fts_trx == NULL) {
+ trx->fts_trx = fts_trx_create(trx);
+ }
+
+ fts_trx_table_t ftt;
+ ftt.table = table;
+ ftt.fts_trx = trx->fts_trx;
+
+ fts_add_doc_from_tuple(&ftt, doc_id, node->row);
+ } else {
+ /* Pass NULL for the columns affected, since an INSERT affects
+ all FTS indexes. */
+ fts_trx_add_op(trx, table, doc_id, FTS_INSERT, NULL);
+ }
}
que_thr_stop_for_mysql_no_error(thr, trx);
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 7e49b2de1e9..99e83779dbd 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -752,6 +752,7 @@ row_purge_upd_exist_or_extern_func(
mem_heap_t* heap;
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
+ ut_ad(!node->table->skip_alter_undo);
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
|| (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
@@ -1035,6 +1036,7 @@ row_purge_record_func(
bool purged = true;
ut_ad(!node->found_clust);
+ ut_ad(!node->table->skip_alter_undo);
clust_index = dict_table_get_first_index(node->table);
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index f968fb780ae..c14af408dda 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -456,6 +456,7 @@ close_table:
dict_table_close(node->table, dict_locked, FALSE);
node->table = NULL;
} else {
+ ut_ad(!node->table->skip_alter_undo);
clust_index = dict_table_get_first_index(node->table);
if (clust_index != NULL) {
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index c452aa889c8..b4aec1f3c4d 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -1144,6 +1144,8 @@ row_undo_mod_parse_undo_rec(
return;
}
+ ut_ad(!node->table->skip_alter_undo);
+
if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) {
close_table:
/* Normally, tables should not disappear or become
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index 91c0a5f50ae..2fcfecd5c11 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -172,6 +172,8 @@ row_undo_search_clust_to_pcur(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
+ ut_ad(!node->table->skip_alter_undo);
+
mtr_start(&mtr);
clust_index = dict_table_get_first_index(node->table);
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 203160b35d6..e204059dd04 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -581,6 +581,7 @@ row_upd_changes_field_size_or_external(
ulint i;
ut_ad(rec_offs_validate(NULL, index, offsets));
+ ut_ad(!index->table->skip_alter_undo);
n_fields = upd_get_n_fields(update);
for (i = 0; i < n_fields; i++) {
@@ -705,6 +706,7 @@ row_upd_rec_in_place(
ulint i;
ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_ad(!index->table->skip_alter_undo);
if (rec_offs_comp(offsets)) {
#ifdef UNIV_DEBUG
@@ -1013,6 +1015,7 @@ row_upd_build_sec_rec_difference_binary(
ut_ad(rec_offs_n_fields(offsets) == dtuple_get_n_fields(entry));
ut_ad(!rec_offs_any_extern(offsets));
ut_ad(!rec_offs_any_default(offsets));
+ ut_ad(!index->table->skip_alter_undo);
update = upd_create(dtuple_get_n_fields(entry), heap);
@@ -1094,6 +1097,7 @@ row_upd_build_difference_binary(
/* This function is used only for a clustered index */
ut_a(dict_index_is_clust(index));
+ ut_ad(!index->table->skip_alter_undo);
update = upd_create(n_fld + n_v_fld, heap);
@@ -1356,6 +1360,8 @@ row_upd_index_replace_new_col_vals_index_pos(
const upd_t* update,
mem_heap_t* heap)
{
+ ut_ad(!index->table->skip_alter_undo);
+
const page_size_t& page_size = dict_table_page_size(index->table);
dtuple_set_info_bits(entry, update->info_bits);
@@ -1410,6 +1416,8 @@ row_upd_index_replace_new_col_vals(
= dict_table_get_first_index(index->table);
const page_size_t& page_size = dict_table_page_size(index->table);
+ ut_ad(!index->table->skip_alter_undo);
+
dtuple_set_info_bits(entry, update->info_bits);
for (i = 0; i < dict_index_get_n_fields(index); i++) {
@@ -1484,6 +1492,8 @@ row_upd_replace_vcol(
ulint i;
ulint n_cols;
+ ut_ad(!table->skip_alter_undo);
+
n_cols = dtuple_get_n_v_fields(row);
for (col_no = 0; col_no < n_cols; col_no++) {
dfield_t* dfield;
@@ -1705,6 +1715,7 @@ row_upd_changes_ord_field_binary_func(
ut_ad(thr);
ut_ad(thr->graph);
ut_ad(thr->graph->trx);
+ ut_ad(!index->table->skip_alter_undo);
n_unique = dict_index_get_n_unique(index);
@@ -1964,6 +1975,8 @@ row_upd_changes_doc_id(
dict_index_t* clust_index;
fts_t* fts = table->fts;
+ ut_ad(!table->skip_alter_undo);
+
clust_index = dict_table_get_first_index(table);
/* Convert from index-specific column number to table-global
@@ -1986,6 +1999,8 @@ row_upd_changes_fts_column(
dict_index_t* clust_index;
fts_t* fts = table->fts;
+ ut_ad(!table->skip_alter_undo);
+
if (upd_fld_is_virtual_col(upd_field)) {
col_no = upd_field->field_no;
return(dict_table_is_fts_column(fts->indexes, col_no, true));
@@ -2836,6 +2851,7 @@ row_upd_clust_rec(
ut_ad(node);
ut_ad(dict_index_is_clust(index));
ut_ad(!thr_get_trx(thr)->in_rollback);
+ ut_ad(!node->table->skip_alter_undo);
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index 1a68e46361b..a9f4cef6579 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -2290,6 +2290,8 @@ trx_undo_prev_version_build(
const bool is_temp = dict_table_is_temporary(index->table);
rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
+ ut_ad(!index->table->skip_alter_undo);
+
if (trx_undo_get_undo_rec(
roll_ptr, is_temp, heap, rec_trx_id, index->table->name,
&undo_rec)) {
diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp
index 0b0de7a41ed..6641ebda551 100644
--- a/storage/mroonga/ha_mroonga.cpp
+++ b/storage/mroonga/ha_mroonga.cpp
@@ -542,6 +542,16 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
inspected = "HA_EXTRA_DETACH_CHILDREN";
break;
case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
+ inspected = "HA_EXTRA_STARTING_ORDERED_INDEX_SCAN";
+ break;
+ case HA_EXTRA_BEGIN_ALTER_COPY:
+ inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
+ break;
+ case HA_EXTRA_END_ALTER_COPY:
+ inspected = "HA_EXTRA_END_ALTER_COPY";
+ break;
+ case HA_EXTRA_FAKE_START_STMT:
+ inspected = "HA_EXTRA_FAKE_START_STMT";
break;
#ifdef MRN_HAVE_HA_EXTRA_EXPORT
case HA_EXTRA_EXPORT: