Skip to content

Commit f6a7730

Browse files
committed
MDEV-16490: It's possible to make a system versioned table without any versioning field
* do not allow versioned table to be without versioned (non-system) fields * prohibit changing field versioning, when removing table versioning * handle CREATE...SELECT as well
1 parent 604f80e commit f6a7730

File tree

8 files changed

+158
-56
lines changed

8 files changed

+158
-56
lines changed

mysql-test/suite/versioning/r/alter.result

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,45 @@ create or replace table t1 (f1 int) with system versioning;
639639
alter table t1 drop system versioning, add f2 int with system versioning;
640640
ERROR HY000: Table `t1` is not system-versioned
641641
drop table t1;
642+
# MDEV-16490 It's possible to make a system versioned table without any versioning field
643+
set @@system_versioning_alter_history=keep;
644+
create or replace table t (a int) with system versioning engine=innodb;
645+
alter table t change column a a int without system versioning;
646+
ERROR HY000: Table `t` must have at least one versioned column
647+
alter table t
648+
change column a a int without system versioning,
649+
add column b int with system versioning;
650+
show create table t;
651+
Table Create Table
652+
t CREATE TABLE `t` (
653+
`a` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING,
654+
`b` int(11) DEFAULT NULL
655+
) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
656+
alter table t
657+
change column a new_a int,
658+
drop system versioning;
659+
show create table t;
660+
Table Create Table
661+
t CREATE TABLE `t` (
662+
`new_a` int(11) DEFAULT NULL,
663+
`b` int(11) DEFAULT NULL
664+
) ENGINE=InnoDB DEFAULT CHARSET=latin1
665+
alter table t add system versioning;
666+
alter table t change column new_a a int without system versioning;
667+
show create table t;
668+
Table Create Table
669+
t CREATE TABLE `t` (
670+
`a` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING,
671+
`b` int(11) DEFAULT NULL
672+
) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING
673+
alter table t
674+
add column c int,
675+
change column c c int without system versioning,
676+
change column b b int without system versioning;
677+
ERROR HY000: Table `t` must have at least one versioned column
678+
alter table t
679+
add column c int without system versioning,
680+
change column c c int,
681+
change column b b int without system versioning;
682+
drop database test;
683+
create database test;

mysql-test/suite/versioning/r/create.result

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,3 +515,13 @@ row_end datetime(6) generated always as row end,
515515
period for system_time(row_start, row_end)
516516
) with system versioning;
517517
ERROR HY000: `row_start` must be of type TIMESTAMP(6) for system-versioned table `t`
518+
# MDEV-16490 It's possible to make a system versioned table without any versioning field
519+
create or replace table t1 (x int without system versioning)
520+
with system versioning
521+
select 1 as y;
522+
create or replace table t1 (x int without system versioning)
523+
with system versioning
524+
select 1 as x;
525+
ERROR HY000: Table `t1` must have at least one versioned column
526+
drop database test;
527+
create database test;

mysql-test/suite/versioning/t/alter.test

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,3 +542,37 @@ alter table t1 drop system versioning, add f2 int with system versioning;
542542

543543
drop table t1;
544544
--source suite/versioning/common_finish.inc
545+
--echo # MDEV-16490 It's possible to make a system versioned table without any versioning field
546+
547+
set @@system_versioning_alter_history=keep;
548+
create or replace table t (a int) with system versioning engine=innodb;
549+
--error ER_VERS_TABLE_MUST_HAVE_COLUMNS
550+
alter table t change column a a int without system versioning;
551+
552+
alter table t
553+
change column a a int without system versioning,
554+
add column b int with system versioning;
555+
show create table t;
556+
557+
alter table t
558+
change column a new_a int,
559+
drop system versioning;
560+
show create table t;
561+
562+
alter table t add system versioning;
563+
alter table t change column new_a a int without system versioning;
564+
show create table t;
565+
566+
--error ER_VERS_TABLE_MUST_HAVE_COLUMNS
567+
alter table t
568+
add column c int,
569+
change column c c int without system versioning,
570+
change column b b int without system versioning;
571+
572+
alter table t
573+
add column c int without system versioning,
574+
change column c c int,
575+
change column b b int without system versioning;
576+
577+
drop database test;
578+
create database test;

mysql-test/suite/versioning/t/create.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,14 @@ create table t (
396396
) with system versioning;
397397

398398
--source suite/versioning/common_finish.inc
399+
--echo # MDEV-16490 It's possible to make a system versioned table without any versioning field
400+
create or replace table t1 (x int without system versioning)
401+
with system versioning
402+
select 1 as y;
403+
--error ER_VERS_TABLE_MUST_HAVE_COLUMNS
404+
create or replace table t1 (x int without system versioning)
405+
with system versioning
406+
select 1 as x;
407+
408+
drop database test;
409+
create database test;

sql/handler.cc

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7164,8 +7164,7 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info)
71647164

71657165

71667166
bool Table_scope_and_contents_source_st::vers_fix_system_fields(
7167-
THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table,
7168-
bool create_select)
7167+
THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table)
71697168
{
71707169
DBUG_ASSERT(!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING));
71717170

@@ -7205,40 +7204,55 @@ bool Table_scope_and_contents_source_st::vers_fix_system_fields(
72057204
if (vers_info.fix_implicit(thd, alter_info))
72067205
return true;
72077206

7208-
int plain_cols= 0; // columns don't have WITH or WITHOUT SYSTEM VERSIONING
7209-
int vers_cols= 0; // columns have WITH SYSTEM VERSIONING
7210-
it.rewind();
7211-
while (const Create_field *f= it++)
7212-
{
7213-
if (vers_info.is_start(*f) || vers_info.is_end(*f))
7214-
continue;
7215-
7216-
if (f->versioning == Column_definition::VERSIONING_NOT_SET)
7217-
plain_cols++;
7218-
else if (f->versioning == Column_definition::WITH_VERSIONING)
7219-
vers_cols++;
7220-
}
7221-
7222-
if (!thd->lex->tmp_table() &&
7223-
// CREATE from SELECT (Create_fields are not yet added)
7224-
!create_select && vers_cols == 0 && (plain_cols == 0 || !vers_info))
7225-
{
7226-
my_error(ER_VERS_TABLE_MUST_HAVE_COLUMNS, MYF(0),
7227-
create_table.table_name.str);
7228-
return true;
7229-
}
7230-
72317207
return false;
72327208
}
72337209

72347210

72357211
bool Table_scope_and_contents_source_st::vers_check_system_fields(
7236-
THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table)
7212+
THD *thd, Alter_info *alter_info, const Lex_table_name &table_name,
7213+
const Lex_table_name &db, int select_count)
72377214
{
72387215
if (!(options & HA_VERSIONED_TABLE))
72397216
return false;
7240-
return vers_info.check_sys_fields(
7241-
create_table.table_name, create_table.db, alter_info,
7217+
7218+
if (!(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING))
7219+
{
7220+
uint versioned_fields= 0;
7221+
uint fieldnr= 0;
7222+
List_iterator<Create_field> field_it(alter_info->create_list);
7223+
while (Create_field *f= field_it++)
7224+
{
7225+
/*
7226+
The field from the CREATE part can be duplicated in the SELECT part of
7227+
CREATE...SELECT. In that case double counts should be avoided.
7228+
select_create::create_table_from_items just pushes the fields back into
7229+
the create_list, without additional manipulations, so the fields from
7230+
SELECT go last there.
7231+
*/
7232+
bool is_dup= false;
7233+
if (fieldnr >= alter_info->create_list.elements - select_count)
7234+
{
7235+
List_iterator<Create_field> dup_it(alter_info->create_list);
7236+
for (Create_field *dup= dup_it++; !is_dup && dup != f; dup= dup_it++)
7237+
is_dup= my_strcasecmp(default_charset_info,
7238+
dup->field_name.str, f->field_name.str) == 0;
7239+
}
7240+
7241+
if (!(f->flags & VERS_UPDATE_UNVERSIONED_FLAG) && !is_dup)
7242+
versioned_fields++;
7243+
fieldnr++;
7244+
}
7245+
if (versioned_fields == VERSIONING_FIELDS)
7246+
{
7247+
my_error(ER_VERS_TABLE_MUST_HAVE_COLUMNS, MYF(0), table_name.str);
7248+
return true;
7249+
}
7250+
}
7251+
7252+
if (!(alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING))
7253+
return false;
7254+
7255+
return vers_info.check_sys_fields(table_name, db, alter_info,
72427256
ha_check_storage_engine_flag(db_type, HTON_NATIVE_SYS_VERSIONING));
72437257
}
72447258

@@ -7343,20 +7357,7 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info,
73437357
return false;
73447358
}
73457359

7346-
if (fix_implicit(thd, alter_info))
7347-
return true;
7348-
7349-
if (alter_info->flags & ALTER_ADD_SYSTEM_VERSIONING)
7350-
{
7351-
const bool can_native=
7352-
ha_check_storage_engine_flag(create_info->db_type,
7353-
HTON_NATIVE_SYS_VERSIONING) ||
7354-
create_info->db_type->db_type == DB_TYPE_PARTITION_DB;
7355-
if (check_sys_fields(table_name, share->db, alter_info, can_native))
7356-
return true;
7357-
}
7358-
7359-
return false;
7360+
return fix_implicit(thd, alter_info);
73607361
}
73617362

73627363
bool

sql/handler.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,11 +2104,12 @@ struct Table_scope_and_contents_source_st:
21042104
}
21052105

21062106
bool vers_fix_system_fields(THD *thd, Alter_info *alter_info,
2107-
const TABLE_LIST &create_table,
2108-
bool create_select= false);
2107+
const TABLE_LIST &create_table);
21092108

21102109
bool vers_check_system_fields(THD *thd, Alter_info *alter_info,
2111-
const TABLE_LIST &create_table);
2110+
const Lex_table_name &table_name,
2111+
const Lex_table_name &db,
2112+
int select_count= 0);
21122113

21132114
};
21142115

sql/sql_insert.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4185,8 +4185,7 @@ TABLE *select_create::create_table_from_items(THD *thd,
41854185
if (!opt_explicit_defaults_for_timestamp)
41864186
promote_first_timestamp_column(&alter_info->create_list);
41874187

4188-
if (create_info->vers_fix_system_fields(thd, alter_info, *create_table,
4189-
true))
4188+
if (create_info->vers_fix_system_fields(thd, alter_info, *create_table))
41904189
DBUG_RETURN(NULL);
41914190

41924191
while ((item=it++))
@@ -4225,7 +4224,10 @@ TABLE *select_create::create_table_from_items(THD *thd,
42254224
alter_info->create_list.push_back(cr_field, thd->mem_root);
42264225
}
42274226

4228-
if (create_info->vers_check_system_fields(thd, alter_info, *create_table))
4227+
if (create_info->vers_check_system_fields(thd, alter_info,
4228+
create_table->table_name,
4229+
create_table->db,
4230+
select_field_count))
42294231
DBUG_RETURN(NULL);
42304232

42314233
DEBUG_SYNC(thd,"create_table_select_before_create");

sql/sql_table.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8511,13 +8511,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
85118511
}
85128512
}
85138513

8514-
if (table->versioned() && !(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING) &&
8515-
new_create_list.elements == VERSIONING_FIELDS)
8516-
{
8517-
my_error(ER_VERS_TABLE_MUST_HAVE_COLUMNS, MYF(0), table->s->table_name.str);
8518-
goto err;
8519-
}
8520-
85218514
if (!create_info->comment.str)
85228515
{
85238516
create_info->comment.str= table->s->comment.str;
@@ -9553,6 +9546,12 @@ do_continue:;
95539546
DBUG_RETURN(true);
95549547
}
95559548

9549+
if (create_info->vers_check_system_fields(thd, alter_info,
9550+
table->s->table_name, table->s->db))
9551+
{
9552+
DBUG_RETURN(true);
9553+
}
9554+
95569555
set_table_default_charset(thd, create_info, &alter_ctx.db);
95579556

95589557
if (!opt_explicit_defaults_for_timestamp)
@@ -11170,7 +11169,9 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1117011169
else
1117111170
{
1117211171
if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table) ||
11173-
create_info.vers_check_system_fields(thd, &alter_info, *create_table))
11172+
create_info.vers_check_system_fields(thd, &alter_info,
11173+
create_table->table_name,
11174+
create_table->db))
1117411175
goto end_with_restore_list;
1117511176

1117611177
/*

0 commit comments

Comments
 (0)