summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2018-06-09 16:06:39 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-06-20 19:23:48 +0300
commit9dc81f7d387050dd62f2307b15c63c3a3f5ea1b0 (patch)
treec921284d68bfeb56cfcda8b30cd5927c9f10ec2c
parentff09512e07045b0997265d37c45f075daebe9531 (diff)
downloadmariadb-git-9dc81f7d387050dd62f2307b15c63c3a3f5ea1b0.tar.gz
MDEV-16330 Allow instant change of WITH SYSTEM VERSIONING column attribute
Changing columns WITH/WITHOUT SYSTEM VERSIONING doens't require to read data at all. Thus it should be an instant operation. Patch also fixes a bug when ALTER_COLUMN_UNVERSIONED wasn't passed to InnoDB to change its internal structures. change_field_versioning_try(): apply WITH/WITHOUT SYSTEM VERSIONING change in SYS_COLUMNS for one field. change_fields_versioning_try(): apply WITH/WITHOUT SYSTEM VERSIONING change in SYS_COLUMNS for every changed field in a table. change_fields_versioning_cache(): update cache for versioning property of columns.
-rw-r--r--mysql-test/suite/versioning/r/trx_id.result96
-rw-r--r--mysql-test/suite/versioning/r/trx_id_versioning_attribute_persistence.result86
-rw-r--r--mysql-test/suite/versioning/t/trx_id.test83
-rw-r--r--mysql-test/suite/versioning/t/trx_id_versioning_attribute_persistence.test87
-rw-r--r--sql/sql_table.cc18
-rw-r--r--storage/innobase/handler/handler0alter.cc192
6 files changed, 551 insertions, 11 deletions
diff --git a/mysql-test/suite/versioning/r/trx_id.result b/mysql-test/suite/versioning/r/trx_id.result
index 7b2ea04985d..2e0db5f2cde 100644
--- a/mysql-test/suite/versioning/r/trx_id.result
+++ b/mysql-test/suite/versioning/r/trx_id.result
@@ -379,3 +379,99 @@ DROP TABLE tts;
DROP TABLE ttx;
DROP FUNCTION fts;
DROP FUNCTION ftx;
+#
+# MDEV-16330 Allow instant change of WITH SYSTEM VERSIONING column attribute
+#
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+CREATE TABLE t (
+a INT,
+b INT,
+row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+INSERT INTO t VALUES (1,1);
+# without table rebuild
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='a';
+prtype
+50179
+ALTER TABLE t
+CHANGE a a INT WITHOUT SYSTEM VERSIONING;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='a';
+prtype
+1027
+UPDATE t SET a=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+COUNT(*)
+1
+# with table rebuild
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='a';
+prtype
+1027
+ALTER TABLE t
+CHANGE a a INT WITH SYSTEM VERSIONING,
+ADD PRIMARY KEY pk(a);
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='a';
+prtype
+50435
+UPDATE t SET a=1;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+COUNT(*)
+2
+SHOW CREATE TABLE t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `row_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START INVISIBLE,
+ `row_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END INVISIBLE,
+ PRIMARY KEY (`a`,`row_end`),
+ PERIOD FOR SYSTEM_TIME (`row_start`, `row_end`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+# handles VIRTUAL columns too
+CREATE OR REPLACE TABLE t (
+a INT AS (b + 1),
+b INT,
+row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+INSERT INTO t VALUES (DEFAULT, 1);
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='b';
+prtype
+50179
+ALTER TABLE t
+CHANGE b b INT WITHOUT SYSTEM VERSIONING;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ON c.table_id=t.table_id
+WHERE t.name='test/t' AND c.name='b';
+prtype
+1027
+UPDATE t SET b=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+COUNT(*)
+1
+DROP TABLE t;
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=ERROR;
diff --git a/mysql-test/suite/versioning/r/trx_id_versioning_attribute_persistence.result b/mysql-test/suite/versioning/r/trx_id_versioning_attribute_persistence.result
new file mode 100644
index 00000000000..bf555fb2a7d
--- /dev/null
+++ b/mysql-test/suite/versioning/r/trx_id_versioning_attribute_persistence.result
@@ -0,0 +1,86 @@
+CREATE OR REPLACE TABLE t1 (
+a INT,
+b INT,
+row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+CREATE OR REPLACE TABLE t2 (
+a INT WITHOUT SYSTEM VERSIONING,
+b INT,
+row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+INSERT INTO t1 VALUES (1,1);
+INSERT INTO t2 VALUES (1,1);
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+# without rebuild
+ALTER TABLE t1
+CHANGE a a INT WITHOUT SYSTEM VERSIONING,
+ALGORITHM=INSTANT;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+ALTER TABLE t2
+CHANGE a a INT WITH SYSTEM VERSIONING,
+ADD PRIMARY KEY pk (a),
+ALGORITHM=INSTANT;
+ERROR 0A000: ALGORITHM=INSTANT is not supported for this operation. Try ALGORITHM=INPLACE
+# with rebuild
+ALTER TABLE t2
+CHANGE a a INT WITH SYSTEM VERSIONING,
+ADD PRIMARY KEY pk (a);
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+UPDATE t1 SET a=2;
+SELECT COUNT(*) FROM t1 FOR SYSTEM_TIME ALL;
+COUNT(*)
+1
+UPDATE t2 SET a=2;
+SELECT COUNT(*) FROM t2 FOR SYSTEM_TIME ALL;
+COUNT(*)
+2
+DROP TABLE t1, t2;
+# rollback ALTER TABLE: nothing should change
+CREATE TABLE t (
+a INT,
+b INT,
+row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+INSERT INTO t VALUES (1, 1);
+SELECT C.PRTYPE FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS C
+JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t ON C.TABLE_ID=t.TABLE_ID
+WHERE t.NAME='test/t' AND C.NAME='b';
+PRTYPE
+50179
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+SET @SAVED_DEBUG_DBUG = @@SESSION.DEBUG_DBUG;
+SET DEBUG_DBUG='+d,ib_commit_inplace_fail_1';
+ALTER TABLE t
+CHANGE b b INT WITHOUT SYSTEM VERSIONING;
+ERROR HY000: Internal error: Injected error!
+SET DEBUG_DBUG = @SAVED_DEBUG_DBUG;
+SELECT C.PRTYPE FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS C
+JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t ON C.TABLE_ID=t.TABLE_ID
+WHERE t.NAME='test/t' AND C.NAME='b';
+PRTYPE
+50179
+SHOW CREATE TABLE t;
+Table Create Table
+t CREATE TABLE `t` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL,
+ `row_start` bigint(20) unsigned GENERATED ALWAYS AS ROW START INVISIBLE,
+ `row_end` bigint(20) unsigned GENERATED ALWAYS AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME (`row_start`, `row_end`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+COUNT(*)
+1
+UPDATE t SET b=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+COUNT(*)
+2
+DROP TABLE t;
diff --git a/mysql-test/suite/versioning/t/trx_id.test b/mysql-test/suite/versioning/t/trx_id.test
index aab28d1057c..35ba6595440 100644
--- a/mysql-test/suite/versioning/t/trx_id.test
+++ b/mysql-test/suite/versioning/t/trx_id.test
@@ -1,5 +1,4 @@
-- source include/have_innodb.inc
--- source include/not_embedded.inc
set default_storage_engine= innodb;
@@ -411,3 +410,85 @@ DROP TABLE tts;
DROP TABLE ttx;
DROP FUNCTION fts;
DROP FUNCTION ftx;
+
+--echo #
+--echo # MDEV-16330 Allow instant change of WITH SYSTEM VERSIONING column attribute
+--echo #
+
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+CREATE TABLE t (
+ a INT,
+ b INT,
+ row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+ row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+
+INSERT INTO t VALUES (1,1);
+
+--echo # without table rebuild
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='a';
+--enable_info
+ALTER TABLE t
+ CHANGE a a INT WITHOUT SYSTEM VERSIONING;
+--disable_info
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='a';
+
+UPDATE t SET a=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+
+--echo # with table rebuild
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='a';
+--enable_info
+ALTER TABLE t
+ CHANGE a a INT WITH SYSTEM VERSIONING,
+ ADD PRIMARY KEY pk(a);
+--disable_info
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='a';
+
+UPDATE t SET a=1;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+
+SHOW CREATE TABLE t;
+
+-- echo # handles VIRTUAL columns too
+CREATE OR REPLACE TABLE t (
+ a INT AS (b + 1),
+ b INT,
+ row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+ row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+
+INSERT INTO t VALUES (DEFAULT, 1);
+
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='b';
+--enable_info
+ALTER TABLE t
+ CHANGE b b INT WITHOUT SYSTEM VERSIONING;
+--disable_info
+SELECT c.prtype FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS c
+ INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t
+ ON c.table_id=t.table_id
+ WHERE t.name='test/t' AND c.name='b';
+
+UPDATE t SET b=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+
+DROP TABLE t;
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=ERROR;
diff --git a/mysql-test/suite/versioning/t/trx_id_versioning_attribute_persistence.test b/mysql-test/suite/versioning/t/trx_id_versioning_attribute_persistence.test
new file mode 100644
index 00000000000..4e92ee247e4
--- /dev/null
+++ b/mysql-test/suite/versioning/t/trx_id_versioning_attribute_persistence.test
@@ -0,0 +1,87 @@
+-- source include/have_innodb.inc
+-- source include/have_debug.inc
+
+CREATE OR REPLACE TABLE t1 (
+ a INT,
+ b INT,
+ row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+ row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+
+CREATE OR REPLACE TABLE t2 (
+ a INT WITHOUT SYSTEM VERSIONING,
+ b INT,
+ row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+ row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+
+INSERT INTO t1 VALUES (1,1);
+INSERT INTO t2 VALUES (1,1);
+
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+
+--enable_info
+--echo # without rebuild
+ALTER TABLE t1
+ CHANGE a a INT WITHOUT SYSTEM VERSIONING,
+ ALGORITHM=INSTANT;
+
+--error ER_ALTER_OPERATION_NOT_SUPPORTED
+ALTER TABLE t2
+ CHANGE a a INT WITH SYSTEM VERSIONING,
+ ADD PRIMARY KEY pk (a),
+ ALGORITHM=INSTANT;
+
+--echo # with rebuild
+ALTER TABLE t2
+ CHANGE a a INT WITH SYSTEM VERSIONING,
+ ADD PRIMARY KEY pk (a);
+--disable_info
+
+--source include/restart_mysqld.inc
+
+UPDATE t1 SET a=2;
+SELECT COUNT(*) FROM t1 FOR SYSTEM_TIME ALL;
+
+UPDATE t2 SET a=2;
+SELECT COUNT(*) FROM t2 FOR SYSTEM_TIME ALL;
+
+DROP TABLE t1, t2;
+
+--echo # rollback ALTER TABLE: nothing should change
+CREATE TABLE t (
+ a INT,
+ b INT,
+ row_start BIGINT UNSIGNED AS ROW START INVISIBLE,
+ row_end BIGINT UNSIGNED AS ROW END INVISIBLE,
+ PERIOD FOR SYSTEM_TIME(row_start, row_end)
+) WITH SYSTEM VERSIONING ENGINE=INNODB;
+
+INSERT INTO t VALUES (1, 1);
+
+SELECT C.PRTYPE FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS C
+ JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t ON C.TABLE_ID=t.TABLE_ID
+ WHERE t.NAME='test/t' AND C.NAME='b';
+
+SET @@SYSTEM_VERSIONING_ALTER_HISTORY=KEEP;
+
+SET @SAVED_DEBUG_DBUG = @@SESSION.DEBUG_DBUG;
+SET DEBUG_DBUG='+d,ib_commit_inplace_fail_1';
+--error ER_INTERNAL_ERROR
+ALTER TABLE t
+ CHANGE b b INT WITHOUT SYSTEM VERSIONING;
+SET DEBUG_DBUG = @SAVED_DEBUG_DBUG;
+
+SELECT C.PRTYPE FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS AS C
+ JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLES AS t ON C.TABLE_ID=t.TABLE_ID
+ WHERE t.NAME='test/t' AND C.NAME='b';
+
+SHOW CREATE TABLE t;
+
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+UPDATE t SET b=11;
+SELECT COUNT(*) FROM t FOR SYSTEM_TIME ALL;
+
+DROP TABLE t;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 2b0c4439146..ac65fbb90c2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6535,15 +6535,15 @@ static bool fill_alter_inplace_info(THD *thd,
ALTER_DROP_INDEX are replaced with versions that have higher granuality.
*/
- ha_alter_info->handler_flags|= (alter_info->flags &
- ~(ALTER_ADD_INDEX |
- ALTER_DROP_INDEX |
- ALTER_PARSER_ADD_COLUMN |
- ALTER_PARSER_DROP_COLUMN |
- ALTER_COLUMN_ORDER |
- ALTER_RENAME_COLUMN |
- ALTER_CHANGE_COLUMN |
- ALTER_COLUMN_UNVERSIONED));
+ alter_table_operations flags_to_remove=
+ ALTER_ADD_INDEX | ALTER_DROP_INDEX | ALTER_PARSER_ADD_COLUMN |
+ ALTER_PARSER_DROP_COLUMN | ALTER_COLUMN_ORDER | ALTER_RENAME_COLUMN |
+ ALTER_CHANGE_COLUMN;
+
+ if (!table->file->native_versioned())
+ flags_to_remove|= ALTER_COLUMN_UNVERSIONED;
+
+ ha_alter_info->handler_flags|= (alter_info->flags & ~flags_to_remove);
/*
Comparing new and old default values of column is cumbersome.
So instead of using such a comparison for detecting if default
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 08963ceff3e..435b2b2403f 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -87,7 +87,6 @@ static const alter_table_operations INNOBASE_ALTER_REBUILD
/*
| ALTER_STORED_COLUMN_TYPE
*/
- | ALTER_COLUMN_UNVERSIONED
| ALTER_ADD_SYSTEM_VERSIONING
| ALTER_DROP_SYSTEM_VERSIONING
;
@@ -128,6 +127,7 @@ static const alter_table_operations INNOBASE_ALTER_INSTANT
| ALTER_ADD_VIRTUAL_COLUMN
| INNOBASE_FOREIGN_OPERATIONS
| ALTER_COLUMN_EQUAL_PACK_LENGTH
+ | ALTER_COLUMN_UNVERSIONED
| ALTER_DROP_VIRTUAL_COLUMN;
struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
@@ -8433,6 +8433,188 @@ innobase_update_foreign_cache(
DBUG_RETURN(err);
}
+/** Changes SYS_COLUMNS.PRTYPE for one column.
+@param[in,out] trx transaction
+@param[in] table_name table name
+@param[in] tableid table ID as in SYS_TABLES
+@param[in] pos column position
+@param[in] prtype new precise type
+@return boolean flag
+@retval true on failure
+@retval false on success */
+static
+bool
+change_field_versioning_try(
+ trx_t* trx,
+ const char* table_name,
+ const table_id_t tableid,
+ const ulint pos,
+ const ulint prtype)
+{
+ DBUG_ENTER("change_field_versioning_try");
+
+ pars_info_t* info = pars_info_create();
+
+ pars_info_add_int4_literal(info, "prtype", prtype);
+ pars_info_add_ull_literal(info,"tableid", tableid);
+ pars_info_add_int4_literal(info, "pos", pos);
+
+ dberr_t error = que_eval_sql(info,
+ "PROCEDURE CHANGE_COLUMN_MTYPE () IS\n"
+ "BEGIN\n"
+ "UPDATE SYS_COLUMNS SET PRTYPE=:prtype\n"
+ "WHERE TABLE_ID=:tableid AND POS=:pos;\n"
+ "END;\n",
+ false, trx);
+
+ if (error != DB_SUCCESS) {
+ my_error_innodb(error, table_name, 0);
+ trx->error_state = DB_SUCCESS;
+ trx->op_info = "";
+ DBUG_RETURN(true);
+ }
+
+ DBUG_RETURN(false);
+}
+
+/** Changes fields WITH/WITHOUT SYSTEM VERSIONING property in SYS_COLUMNS.
+@param[in] ha_alter_info alter info
+@param[in] ctx alter inplace context
+@param[in] trx transaction
+@param[in] table old table
+@return boolean flag
+@retval true on failure
+@retval false on success */
+static
+bool
+change_fields_versioning_try(
+ const Alter_inplace_info* ha_alter_info,
+ const ha_innobase_inplace_ctx* ctx,
+ trx_t* trx,
+ const TABLE* table)
+{
+ DBUG_ENTER("change_fields_versioning_try");
+
+ DBUG_ASSERT(ha_alter_info);
+ DBUG_ASSERT(ctx);
+
+ if (!(ha_alter_info->handler_flags & ALTER_COLUMN_UNVERSIONED)){
+ DBUG_RETURN(false);
+ }
+
+ uint virtual_count = 0;
+
+ List_iterator_fast<Create_field> it(
+ ha_alter_info->alter_info->create_list);
+
+ for (uint i = 0; i < table->s->fields; i++) {
+ const Field* field = table->field[i];
+
+ if (innobase_is_v_fld(field)) {
+ virtual_count++;
+ continue;
+ }
+
+ const Create_field* create_field = NULL;
+ while (const Create_field* cf = it++) {
+ if (cf->field == field) {
+ create_field = cf;
+ break;
+ }
+ }
+ it.rewind();
+ DBUG_ASSERT(create_field);
+
+ if (create_field->versioning
+ == Column_definition::VERSIONING_NOT_SET) {
+ continue;
+ }
+
+ const dict_table_t* new_table = ctx->new_table;
+ ulint pos = i - virtual_count;
+ const dict_col_t* col = dict_table_get_nth_col(new_table, pos);
+
+ DBUG_ASSERT(!col->vers_sys_start());
+ DBUG_ASSERT(!col->vers_sys_end());
+
+ ulint new_prtype
+ = create_field->versioning
+ == Column_definition::WITHOUT_VERSIONING
+ ? col->prtype & ~DATA_VERSIONED
+ : col->prtype | DATA_VERSIONED;
+
+ if (change_field_versioning_try(trx, table->s->table_name.str,
+ new_table->id, pos,
+ new_prtype)) {
+ DBUG_RETURN(true);
+ }
+ }
+
+ DBUG_RETURN(false);
+}
+
+/** Changes WITH/WITHOUT SYSTEM VERSIONING for fields
+in the data dictionary cache.
+@param ha_alter_info Data used during in-place alter
+@param ctx In-place ALTER TABLE context
+@param table MySQL table as it is before the ALTER operation */
+static
+void
+change_fields_versioning_cache(
+ Alter_inplace_info* ha_alter_info,
+ const ha_innobase_inplace_ctx* ctx,
+ const TABLE* table)
+{
+ DBUG_ENTER("change_fields_versioning");
+
+ DBUG_ASSERT(ha_alter_info);
+ DBUG_ASSERT(ctx);
+ DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_COLUMN_UNVERSIONED);
+
+ uint virtual_count = 0;
+
+ List_iterator_fast<Create_field> it(
+ ha_alter_info->alter_info->create_list);
+
+ for (uint i = 0; i < table->s->fields; i++) {
+ const Field* field = table->field[i];
+
+ if (innobase_is_v_fld(field)) {
+ virtual_count++;
+ continue;
+ }
+
+ const Create_field* create_field = NULL;
+ while (const Create_field* cf = it++) {
+ if (cf->field == field) {
+ create_field = cf;
+ break;
+ }
+ }
+ it.rewind();
+ DBUG_ASSERT(create_field);
+
+ dict_col_t* col
+ = dict_table_get_nth_col(ctx->new_table, i - virtual_count);
+
+ if (create_field->versioning
+ == Column_definition::WITHOUT_VERSIONING) {
+
+ DBUG_ASSERT(!col->vers_sys_start());
+ DBUG_ASSERT(!col->vers_sys_end());
+ col->prtype &= ~DATA_VERSIONED;
+ } else if (create_field->versioning
+ == Column_definition::WITH_VERSIONING) {
+
+ DBUG_ASSERT(!col->vers_sys_start());
+ DBUG_ASSERT(!col->vers_sys_end());
+ col->prtype |= DATA_VERSIONED;
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
/** Commit the changes made during prepare_inplace_alter_table()
and inplace_alter_table() inside the data dictionary tables,
when rebuilding the table.
@@ -8742,6 +8924,10 @@ commit_try_norebuild(
DBUG_RETURN(true);
}
+ if (change_fields_versioning_try(ha_alter_info, ctx, trx, old_table)) {
+ DBUG_RETURN(true);
+ }
+
dberr_t error;
/* We altered the table in place. Mark the indexes as committed. */
@@ -8947,6 +9133,10 @@ commit_cache_norebuild(
ha_alter_info, table, ctx->new_table);
}
+ if (ha_alter_info->handler_flags & ALTER_COLUMN_UNVERSIONED) {
+ change_fields_versioning_cache(ha_alter_info, ctx, table);
+ }
+
#ifdef MYSQL_RENAME_INDEX
rename_indexes_in_cache(ctx, ha_alter_info);
#endif