MDEV-16975 Application-time periods: ALTER TABLE
* implicit period constraint is hidden and cannot be dropped independently * create...like and create...select support
This commit is contained in:
parent
b2bd52290a
commit
6294516a56
174
mysql-test/suite/period/r/alter.result
Normal file
174
mysql-test/suite/period/r/alter.result
Normal file
@ -0,0 +1,174 @@
|
||||
set @s= '1992-01-01';
|
||||
set @e= '1999-12-31';
|
||||
create or replace table t (s date, e date);
|
||||
# period start/end columns are implicit NOT NULL
|
||||
alter table t add period for a(s, e);
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `a` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
create or replace table t (s date, e date);
|
||||
alter table t change s s date, add period for a(s, e);
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `a` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
alter table t add id int;
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
`id` int(11) DEFAULT NULL,
|
||||
PERIOD FOR `a` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
alter table t drop id;
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `a` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert t values(@e, @s);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t`
|
||||
alter table t drop constraint a;
|
||||
ERROR HY000: Can't DROP CONSTRAINT `a`. Use DROP PERIOD `a` for this
|
||||
# no-op
|
||||
alter table t drop period if exists for b;
|
||||
Warnings:
|
||||
Note 1091 Can't DROP PERIOD `b`; check that it exists
|
||||
# no-op
|
||||
alter table t add period if not exists for a(e, s);
|
||||
Warnings:
|
||||
Note 1060 Duplicate column name 'a'
|
||||
alter table t drop period if exists for a;
|
||||
# no-op
|
||||
alter table t drop period if exists for a;
|
||||
Warnings:
|
||||
Note 1091 Can't DROP PERIOD `a`; check that it exists
|
||||
alter table t add period for a(s, e), add period if not exists for a(e, s);
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `a` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
alter table t drop period for a;
|
||||
# Constraint is dropped
|
||||
insert t values(@e, @s);
|
||||
alter table t drop period for a;
|
||||
ERROR 42000: Can't DROP PERIOD `a`; check that it exists
|
||||
alter table t add period for a(s, e), drop period for a;
|
||||
ERROR 42000: Can't DROP PERIOD `a`; check that it exists
|
||||
truncate t;
|
||||
alter table t add period for a(s, e);
|
||||
insert t values(@e, @s);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t`
|
||||
alter table t add period for a(s, e), drop period for a;
|
||||
insert t values(@e, @s);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t`
|
||||
alter table t add s1 date not null, add period for b(s1, e), drop period for a;
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
`s1` date NOT NULL,
|
||||
PERIOD FOR `b` (`s1`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert t(s, s1, e) values(@e, @s, @e);
|
||||
insert t(s, s1, e) values(@e, @e, @s);
|
||||
ERROR 23000: CONSTRAINT `b` failed for `test`.`t`
|
||||
create table t1 like t;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
`s1` date NOT NULL,
|
||||
PERIOD FOR `b` (`s1`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
create table t2 (period for b(s,e)) select * from t;
|
||||
ERROR 23000: CONSTRAINT `b` failed for `test`.`t2`
|
||||
create table t2 (period for b(s1,e)) select * from t;
|
||||
# SQL16 11.27 <add table period definition>, Syntax Rules, 5)g)
|
||||
# The declared type of BC1 shall be either DATE or a timestamp type
|
||||
# and shall be equivalent to the declared type of BC2.
|
||||
create or replace table t (s timestamp not null, e timestamp(6) not null);
|
||||
alter table t add period for a(s, e);
|
||||
ERROR HY000: Fields of PERIOD FOR `a` have different types
|
||||
# SQL16 11.27 <add table period definition>, Syntax Rules, 5)c)
|
||||
# No column of T shall have a column name that is equivalent to ATPN.
|
||||
create or replace table t (a int, s date, e date);
|
||||
alter table t add period for a(s, e);
|
||||
ERROR 42S21: Duplicate column name 'a'
|
||||
# SQL16 11.27 <add table period definition>, Syntax Rules, 5)i)
|
||||
# Neither BC1 nor BC2 shall be an identity column, a generated column,
|
||||
# a system-time period start column, or a system-time period end column.
|
||||
create or replace table t (id int primary key,
|
||||
s date,
|
||||
e date generated always as (s+1));
|
||||
alter table t add period for a(s, e);
|
||||
ERROR HY000: Period field `e` cannot be GENERATED ALWAYS AS
|
||||
create or replace table t (id int primary key,
|
||||
s date,
|
||||
e date as (s+1) VIRTUAL);
|
||||
alter table t add period for a(s, e);
|
||||
ERROR HY000: Period field `e` cannot be GENERATED ALWAYS AS
|
||||
create or replace table t (id int primary key, s timestamp(6), e timestamp(6),
|
||||
st timestamp(6) as row start,
|
||||
en timestamp(6) as row end,
|
||||
period for system_time (st, en)) with system versioning;
|
||||
alter table t add period for a(s, en);
|
||||
ERROR HY000: Period field `en` cannot be GENERATED ALWAYS AS
|
||||
# SQL16 11.27 <add table period definition>, Syntax Rules, 5)b)
|
||||
# The table descriptor of T shall not include a period descriptor other
|
||||
# than a system-time period descriptor.
|
||||
alter table t add period for a(s, e);
|
||||
alter table t add period for b(s, e);
|
||||
ERROR HY000: Cannot specify more than one application-time period
|
||||
# SQL16, Part 2, 11.3 <table definition>, Syntax Rules, 2)e)v)2)B)
|
||||
# Let S be the schema identified by the explicit or implicit
|
||||
# <schema name> of TN. Let IDCN be an implementation-dependent
|
||||
# <constraint name> that is not equivalent to the <constraint name> of
|
||||
# any table constraint descriptor included in S. The following
|
||||
# <table constraint definition> is implicit:
|
||||
# CONSTRAINT IDCN CHECK ( CN1 < CN2 )
|
||||
#
|
||||
# Due to the above standard limitation, the constraint name can't always
|
||||
# match the period name. So it matches when possible; and when not, it
|
||||
# is unique not taken name prefixed with period name.
|
||||
create or replace table t (x int, s date, e date,
|
||||
period for mytime(s, e));
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`x` int(11) DEFAULT NULL,
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `mytime` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
alter table t add constraint mytime check (x > 1);
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`x` int(11) DEFAULT NULL,
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `mytime` (`s`, `e`),
|
||||
CONSTRAINT `mytime` CHECK (`x` > 1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert t values (2, @e, @s);
|
||||
ERROR 23000: CONSTRAINT `mytime_1` failed for `test`.`t`
|
||||
alter table t add constraint mytime_1 check (x > 2);
|
||||
insert t values (3, @e, @s);
|
||||
ERROR 23000: CONSTRAINT `mytime_2` failed for `test`.`t`
|
||||
create or replace database test;
|
@ -1,5 +1,7 @@
|
||||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,e));
|
||||
# CONSTRAINT CHECK (s < e) is added implicitly, and shouldn't be shown
|
||||
# this is important for correct command-based replication
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
@ -7,8 +9,7 @@ t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
PERIOD FOR `mytime` (`s`, `e`),
|
||||
CONSTRAINT `CONSTRAINT_1` CHECK (`s` < `e`)
|
||||
PERIOD FOR `mytime` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
create or replace table t (id int primary key, s timestamp(6), e timestamp(6),
|
||||
period for mytime(s,e));
|
||||
@ -19,8 +20,7 @@ t CREATE TABLE `t` (
|
||||
`s` timestamp(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000',
|
||||
`e` timestamp(6) NOT NULL DEFAULT '0000-00-00 00:00:00.000000',
|
||||
PRIMARY KEY (`id`),
|
||||
PERIOD FOR `mytime` (`s`, `e`),
|
||||
CONSTRAINT `CONSTRAINT_1` CHECK (`s` < `e`)
|
||||
PERIOD FOR `mytime` (`s`, `e`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
# SQL16, Part 2, 11.3 <table definition>, Syntax Rules, 2)a)
|
||||
# 2) If a <table period definition> TPD is specified, then:
|
||||
@ -86,7 +86,8 @@ t CREATE TABLE `t` (
|
||||
`s` date NOT NULL,
|
||||
`e` date NOT NULL,
|
||||
PERIOD FOR `mytime` (`s`, `e`),
|
||||
CONSTRAINT `CONSTRAINT_1` CHECK (`s` < `e`),
|
||||
CONSTRAINT `mytime` CHECK (`x` > 1)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert t values (2, '2001-01-01', '2001-01-01');
|
||||
ERROR 23000: CONSTRAINT `mytime_1` failed for `test`.`t`
|
||||
create or replace database test;
|
||||
|
131
mysql-test/suite/period/t/alter.test
Normal file
131
mysql-test/suite/period/t/alter.test
Normal file
@ -0,0 +1,131 @@
|
||||
set @s= '1992-01-01';
|
||||
set @e= '1999-12-31';
|
||||
|
||||
create or replace table t (s date, e date);
|
||||
|
||||
--echo # period start/end columns are implicit NOT NULL
|
||||
alter table t add period for a(s, e);
|
||||
show create table t;
|
||||
|
||||
create or replace table t (s date, e date);
|
||||
alter table t change s s date, add period for a(s, e);
|
||||
show create table t;
|
||||
|
||||
alter table t add id int;
|
||||
show create table t;
|
||||
alter table t drop id;
|
||||
show create table t;
|
||||
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values(@e, @s);
|
||||
|
||||
--error ER_PERIOD_CONSTRAINT_DROP
|
||||
alter table t drop constraint a;
|
||||
|
||||
--echo # no-op
|
||||
alter table t drop period if exists for b;
|
||||
--echo # no-op
|
||||
alter table t add period if not exists for a(e, s);
|
||||
|
||||
alter table t drop period if exists for a;
|
||||
--echo # no-op
|
||||
alter table t drop period if exists for a;
|
||||
|
||||
alter table t add period for a(s, e), add period if not exists for a(e, s);
|
||||
show create table t;
|
||||
|
||||
alter table t drop period for a;
|
||||
--echo # Constraint is dropped
|
||||
insert t values(@e, @s);
|
||||
|
||||
--error ER_CANT_DROP_FIELD_OR_KEY
|
||||
alter table t drop period for a;
|
||||
--error ER_CANT_DROP_FIELD_OR_KEY
|
||||
alter table t add period for a(s, e), drop period for a;
|
||||
|
||||
truncate t;
|
||||
alter table t add period for a(s, e);
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values(@e, @s);
|
||||
alter table t add period for a(s, e), drop period for a;
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values(@e, @s);
|
||||
alter table t add s1 date not null, add period for b(s1, e), drop period for a;
|
||||
show create table t;
|
||||
insert t(s, s1, e) values(@e, @s, @e);
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t(s, s1, e) values(@e, @e, @s);
|
||||
|
||||
create table t1 like t;
|
||||
show create table t1;
|
||||
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
create table t2 (period for b(s,e)) select * from t;
|
||||
|
||||
create table t2 (period for b(s1,e)) select * from t;
|
||||
|
||||
--echo # SQL16 11.27 <add table period definition>, Syntax Rules, 5)g)
|
||||
--echo # The declared type of BC1 shall be either DATE or a timestamp type
|
||||
--echo # and shall be equivalent to the declared type of BC2.
|
||||
create or replace table t (s timestamp not null, e timestamp(6) not null);
|
||||
--error ER_PERIOD_TYPES_MISMATCH
|
||||
alter table t add period for a(s, e);
|
||||
|
||||
--echo # SQL16 11.27 <add table period definition>, Syntax Rules, 5)c)
|
||||
--echo # No column of T shall have a column name that is equivalent to ATPN.
|
||||
create or replace table t (a int, s date, e date);
|
||||
--error ER_DUP_FIELDNAME
|
||||
alter table t add period for a(s, e);
|
||||
|
||||
--echo # SQL16 11.27 <add table period definition>, Syntax Rules, 5)i)
|
||||
--echo # Neither BC1 nor BC2 shall be an identity column, a generated column,
|
||||
--echo # a system-time period start column, or a system-time period end column.
|
||||
create or replace table t (id int primary key,
|
||||
s date,
|
||||
e date generated always as (s+1));
|
||||
--error ER_PERIOD_FIELD_WRONG_ATTRIBUTES
|
||||
alter table t add period for a(s, e);
|
||||
|
||||
create or replace table t (id int primary key,
|
||||
s date,
|
||||
e date as (s+1) VIRTUAL);
|
||||
--error ER_PERIOD_FIELD_WRONG_ATTRIBUTES
|
||||
alter table t add period for a(s, e);
|
||||
|
||||
create or replace table t (id int primary key, s timestamp(6), e timestamp(6),
|
||||
st timestamp(6) as row start,
|
||||
en timestamp(6) as row end,
|
||||
period for system_time (st, en)) with system versioning;
|
||||
--error ER_PERIOD_FIELD_WRONG_ATTRIBUTES
|
||||
alter table t add period for a(s, en);
|
||||
|
||||
--echo # SQL16 11.27 <add table period definition>, Syntax Rules, 5)b)
|
||||
--echo # The table descriptor of T shall not include a period descriptor other
|
||||
--echo # than a system-time period descriptor.
|
||||
alter table t add period for a(s, e);
|
||||
--error ER_MORE_THAN_ONE_PERIOD
|
||||
alter table t add period for b(s, e);
|
||||
|
||||
--echo # SQL16, Part 2, 11.3 <table definition>, Syntax Rules, 2)e)v)2)B)
|
||||
--echo # Let S be the schema identified by the explicit or implicit
|
||||
--echo # <schema name> of TN. Let IDCN be an implementation-dependent
|
||||
--echo # <constraint name> that is not equivalent to the <constraint name> of
|
||||
--echo # any table constraint descriptor included in S. The following
|
||||
--echo # <table constraint definition> is implicit:
|
||||
--echo # CONSTRAINT IDCN CHECK ( CN1 < CN2 )
|
||||
--echo #
|
||||
--echo # Due to the above standard limitation, the constraint name can't always
|
||||
--echo # match the period name. So it matches when possible; and when not, it
|
||||
--echo # is unique not taken name prefixed with period name.
|
||||
create or replace table t (x int, s date, e date,
|
||||
period for mytime(s, e));
|
||||
show create table t;
|
||||
alter table t add constraint mytime check (x > 1);
|
||||
show create table t;
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values (2, @e, @s);
|
||||
alter table t add constraint mytime_1 check (x > 2);
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values (3, @e, @s);
|
||||
|
||||
create or replace database test;
|
@ -1,5 +1,7 @@
|
||||
create or replace table t (id int primary key, s date, e date,
|
||||
period for mytime(s,e));
|
||||
--echo # CONSTRAINT CHECK (s < e) is added implicitly, and shouldn't be shown
|
||||
--echo # this is important for correct command-based replication
|
||||
show create table t;
|
||||
create or replace table t (id int primary key, s timestamp(6), e timestamp(6),
|
||||
period for mytime(s,e));
|
||||
@ -69,5 +71,7 @@ create or replace table t (x int, s date, e date,
|
||||
period for mytime(s, e),
|
||||
constraint mytime check (x > 1));
|
||||
show create table t;
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert t values (2, '2001-01-01', '2001-01-01');
|
||||
|
||||
create or replace database test;
|
||||
|
@ -540,7 +540,7 @@ public:
|
||||
bool stored_in_db;
|
||||
bool utf8; /* Already in utf8 */
|
||||
Item *expr;
|
||||
LEX_CSTRING name; /* Name of constraint */
|
||||
Lex_ident name; /* Name of constraint */
|
||||
/* see VCOL_* (VCOL_FIELD_REF, ...) */
|
||||
uint flags;
|
||||
|
||||
|
@ -7584,18 +7584,18 @@ bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_period_field(const Create_field* f, const char* name,
|
||||
const char* period_name)
|
||||
bool Table_period_info::check_field(const Create_field* f,
|
||||
const Lex_ident& f_name) const
|
||||
{
|
||||
bool res= false;
|
||||
if (!f)
|
||||
{
|
||||
my_error(ER_BAD_FIELD_ERROR, MYF(0), name, period_name);
|
||||
my_error(ER_BAD_FIELD_ERROR, MYF(0), f_name.str, name.str);
|
||||
res= true;
|
||||
}
|
||||
else if (f->type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR)
|
||||
{
|
||||
my_error(ER_WRONG_FIELD_SPEC, MYF(0), name);
|
||||
my_error(ER_WRONG_FIELD_SPEC, MYF(0), f->field_name.str);
|
||||
res= true;
|
||||
}
|
||||
else if (f->vcol_info || f->flags & VERS_SYSTEM_FIELD)
|
||||
@ -7610,10 +7610,13 @@ static bool check_period_field(const Create_field* f, const char* name,
|
||||
bool Table_scope_and_contents_source_st::check_fields(
|
||||
THD *thd, Alter_info *alter_info, TABLE_LIST &create_table)
|
||||
{
|
||||
bool res= vers_check_system_fields(thd, alter_info, create_table);
|
||||
if (res)
|
||||
return true;
|
||||
return vers_check_system_fields(thd, alter_info, create_table)
|
||||
|| check_period_fields(thd, alter_info);
|
||||
}
|
||||
|
||||
bool Table_scope_and_contents_source_st::check_period_fields(
|
||||
THD *thd, Alter_info *alter_info)
|
||||
{
|
||||
if (!period_info.name)
|
||||
return false;
|
||||
|
||||
@ -7639,8 +7642,8 @@ bool Table_scope_and_contents_source_st::check_fields(
|
||||
}
|
||||
}
|
||||
|
||||
res= check_period_field(row_start, period.start.str, period_info.name.str);
|
||||
res= res || check_period_field(row_end, period.end.str, period_info.name.str);
|
||||
bool res= period_info.check_field(row_start, period.start.str)
|
||||
|| period_info.check_field(row_end, period.end.str);
|
||||
if (res)
|
||||
return true;
|
||||
|
||||
@ -7660,9 +7663,14 @@ Table_scope_and_contents_source_st::fix_create_fields(THD *thd,
|
||||
const TABLE_LIST &create_table,
|
||||
bool create_select)
|
||||
{
|
||||
if (vers_fix_system_fields(thd, alter_info, create_table, create_select))
|
||||
return true;
|
||||
return vers_fix_system_fields(thd, alter_info, create_table, create_select)
|
||||
|| fix_period_fields(thd, alter_info);
|
||||
}
|
||||
|
||||
bool
|
||||
Table_scope_and_contents_source_st::fix_period_fields(THD *thd,
|
||||
Alter_info *alter_info)
|
||||
{
|
||||
if (!period_info.name)
|
||||
return false;
|
||||
|
||||
|
@ -1968,11 +1968,15 @@ enum vers_sys_type_t
|
||||
VERS_TRX_ID
|
||||
};
|
||||
|
||||
struct Table_period_info
|
||||
struct Table_period_info: Sql_alloc
|
||||
{
|
||||
Table_period_info() {}
|
||||
Table_period_info() :
|
||||
create_if_not_exists(false),
|
||||
constr(NULL) {}
|
||||
Table_period_info(const char *name_arg, size_t size) :
|
||||
name(name_arg, size) {}
|
||||
name(name_arg, size),
|
||||
create_if_not_exists(false),
|
||||
constr(NULL) {}
|
||||
|
||||
Lex_ident name;
|
||||
|
||||
@ -1986,6 +1990,8 @@ struct Table_period_info
|
||||
Lex_ident end;
|
||||
};
|
||||
start_end_t period;
|
||||
bool create_if_not_exists;
|
||||
Virtual_column_info *constr;
|
||||
|
||||
bool is_set() const
|
||||
{
|
||||
@ -1998,6 +2004,7 @@ struct Table_period_info
|
||||
period.start= start;
|
||||
period.end= end;
|
||||
}
|
||||
bool check_field(const Create_field* f, const Lex_ident& f_name) const;
|
||||
};
|
||||
|
||||
struct Vers_parse_info: public Table_period_info
|
||||
@ -2168,7 +2175,9 @@ struct Table_scope_and_contents_source_st:
|
||||
bool fix_create_fields(THD *thd, Alter_info *alter_info,
|
||||
const TABLE_LIST &create_table,
|
||||
bool create_select= false);
|
||||
bool fix_period_fields(THD *thd, Alter_info *alter_info);
|
||||
bool check_fields(THD *thd, Alter_info *alter_info, TABLE_LIST &create_table);
|
||||
bool check_period_fields(THD *thd, Alter_info *alter_info);
|
||||
|
||||
bool vers_fix_system_fields(THD *thd, Alter_info *alter_info,
|
||||
const TABLE_LIST &create_table,
|
||||
|
@ -7948,3 +7948,6 @@ ER_PERIOD_NOT_FOUND
|
||||
eng "Period %`s is not found in table"
|
||||
ER_PERIOD_COLUMNS_UPDATED
|
||||
eng "Column %`s used in period %`s specified in update SET list"
|
||||
|
||||
ER_PERIOD_CONSTRAINT_DROP
|
||||
eng "Can't DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this"
|
||||
|
@ -288,7 +288,7 @@ public:
|
||||
|
||||
class Alter_drop :public Sql_alloc {
|
||||
public:
|
||||
enum drop_type {KEY, COLUMN, FOREIGN_KEY, CHECK_CONSTRAINT };
|
||||
enum drop_type { KEY, COLUMN, FOREIGN_KEY, CHECK_CONSTRAINT, PERIOD };
|
||||
const char *name;
|
||||
enum drop_type type;
|
||||
bool drop_if_exists;
|
||||
@ -307,6 +307,7 @@ public:
|
||||
{
|
||||
return type == COLUMN ? "COLUMN" :
|
||||
type == CHECK_CONSTRAINT ? "CONSTRAINT" :
|
||||
type == PERIOD ? "PERIOD" :
|
||||
type == KEY ? "INDEX" : "FOREIGN KEY";
|
||||
}
|
||||
};
|
||||
|
@ -4170,8 +4170,7 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
|
||||
if (!opt_explicit_defaults_for_timestamp)
|
||||
promote_first_timestamp_column(&alter_info->create_list);
|
||||
|
||||
if (create_info->vers_fix_system_fields(thd, alter_info, *create_table,
|
||||
true))
|
||||
if (create_info->fix_create_fields(thd, alter_info, *create_table, true))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
while ((item=it++))
|
||||
@ -4210,7 +4209,7 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
|
||||
alter_info->create_list.push_back(cr_field, thd->mem_root);
|
||||
}
|
||||
|
||||
if (create_info->vers_check_system_fields(thd, alter_info, *create_table))
|
||||
if (create_info->check_fields(thd, alter_info, *create_table))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
DEBUG_SYNC(thd,"create_table_select_before_create");
|
||||
|
@ -4277,6 +4277,10 @@ public:
|
||||
int add_period(Lex_ident name, Lex_ident_sys_st start, Lex_ident_sys_st end)
|
||||
{
|
||||
Table_period_info &info= create_info.period_info;
|
||||
|
||||
if (check_exists && info.name.streq(name))
|
||||
return 0;
|
||||
|
||||
if (info.is_set())
|
||||
{
|
||||
my_error(ER_MORE_THAN_ONE_PERIOD, MYF(0));
|
||||
@ -4285,10 +4289,11 @@ public:
|
||||
info.set_period(start, end);
|
||||
info.name= name;
|
||||
|
||||
Virtual_column_info *constr= new Virtual_column_info();
|
||||
constr->expr= lt_creator.create(thd, create_item_ident_nosp(thd, &start),
|
||||
create_item_ident_nosp(thd, &end));
|
||||
add_constraint(&null_clex_str, constr, false);
|
||||
info.constr= new Virtual_column_info();
|
||||
info.constr->expr= lt_creator.create(thd,
|
||||
create_item_ident_nosp(thd, &start),
|
||||
create_item_ident_nosp(thd, &end));
|
||||
add_constraint(&null_clex_str, info.constr, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2417,8 +2417,12 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
|
||||
for (uint i= share->field_check_constraints;
|
||||
i < share->table_check_constraints ; i++)
|
||||
{
|
||||
StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
|
||||
Virtual_column_info *check= table->check_constraints[i];
|
||||
// period constraint is implicit
|
||||
if (share->period.constr_name.streq(check->name))
|
||||
continue;
|
||||
|
||||
StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
|
||||
check->print(&str);
|
||||
|
||||
packet->append(STRING_WITH_LEN(",\n "));
|
||||
|
120
sql/sql_table.cc
120
sql/sql_table.cc
@ -66,6 +66,7 @@ static int check_if_keyname_exists(const char *name,KEY *start, KEY *end);
|
||||
static char *make_unique_key_name(THD *thd, const char *field_name, KEY *start,
|
||||
KEY *end);
|
||||
static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
|
||||
const char *own_name_base,
|
||||
List<Virtual_column_info> *vcol,
|
||||
uint *nr);
|
||||
static const
|
||||
@ -4203,9 +4204,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
while ((check= c_it++))
|
||||
{
|
||||
if (!check->name.length)
|
||||
make_unique_constraint_name(thd, &check->name,
|
||||
{
|
||||
const char *own_name_base= create_info->period_info.constr == check
|
||||
? create_info->period_info.name.str : NULL;
|
||||
|
||||
make_unique_constraint_name(thd, &check->name, own_name_base,
|
||||
&alter_info->check_constraint_list,
|
||||
&nr);
|
||||
}
|
||||
{
|
||||
/* Check that there's no repeating constraint names. */
|
||||
List_iterator_fast<Virtual_column_info>
|
||||
@ -5274,17 +5280,22 @@ make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
|
||||
*/
|
||||
|
||||
static void make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
|
||||
const char *own_name_base,
|
||||
List<Virtual_column_info> *vcol,
|
||||
uint *nr)
|
||||
{
|
||||
char buff[MAX_FIELD_NAME], *end;
|
||||
List_iterator_fast<Virtual_column_info> it(*vcol);
|
||||
|
||||
end=strmov(buff, "CONSTRAINT_");
|
||||
for (;;)
|
||||
end=strmov(buff, own_name_base ? own_name_base : "CONSTRAINT_");
|
||||
for (int round= 0;; round++)
|
||||
{
|
||||
Virtual_column_info *check;
|
||||
char *real_end= int10_to_str((*nr)++, end, 10);
|
||||
char *real_end= end;
|
||||
if (round == 1 && own_name_base)
|
||||
*end++= '_';
|
||||
// if own_base_name provided, try it first
|
||||
if (round != 0 || !own_name_base)
|
||||
real_end= int10_to_str((*nr)++, end, 10);
|
||||
it.rewind();
|
||||
while ((check= it++))
|
||||
{
|
||||
@ -5914,6 +5925,7 @@ static bool is_candidate_key(KEY *key)
|
||||
thd Thread object.
|
||||
table The altered table.
|
||||
alter_info List of columns and indexes to create
|
||||
period_info Application-time period info
|
||||
|
||||
DESCRIPTION
|
||||
Looks for the IF [NOT] EXISTS options, checks the states and remove items
|
||||
@ -5924,7 +5936,8 @@ static bool is_candidate_key(KEY *key)
|
||||
*/
|
||||
|
||||
static void
|
||||
handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
|
||||
handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info,
|
||||
Table_period_info *period_info)
|
||||
{
|
||||
Field **f_ptr;
|
||||
DBUG_ENTER("handle_if_exists_option");
|
||||
@ -6110,6 +6123,11 @@ drop_create_field:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (drop->type == Alter_drop::PERIOD)
|
||||
{
|
||||
if (table->s->period.name.streq(drop->name))
|
||||
remove_drop= FALSE;
|
||||
}
|
||||
else /* Alter_drop::KEY and Alter_drop::FOREIGN_KEY */
|
||||
{
|
||||
uint n_key;
|
||||
@ -6390,6 +6408,26 @@ remove_key:
|
||||
}
|
||||
}
|
||||
|
||||
/* ADD PERIOD */
|
||||
|
||||
if (period_info->create_if_not_exists && table->s->period.name
|
||||
&& table->s->period.name.streq(period_info->name))
|
||||
{
|
||||
DBUG_ASSERT(period_info->is_set());
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_DUP_FIELDNAME, ER_THD(thd, ER_DUP_FIELDNAME),
|
||||
period_info->name.str, table->s->table_name.str);
|
||||
|
||||
List_iterator<Virtual_column_info> vit(alter_info->check_constraint_list);
|
||||
while (vit++ != period_info->constr)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
vit.remove();
|
||||
|
||||
*period_info= {};
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -7792,6 +7830,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
Create_field *def;
|
||||
Field **f_ptr,*field;
|
||||
MY_BITMAP *dropped_fields= NULL; // if it's NULL - no dropped fields
|
||||
bool drop_period= false;
|
||||
DBUG_ENTER("mysql_prepare_alter_table");
|
||||
|
||||
/*
|
||||
@ -8356,6 +8395,35 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
}
|
||||
}
|
||||
|
||||
if (table->s->period.name)
|
||||
{
|
||||
drop_it.rewind();
|
||||
Alter_drop *drop;
|
||||
for (bool found= false; !found && (drop= drop_it++); )
|
||||
{
|
||||
found= drop->type == Alter_drop::PERIOD &&
|
||||
table->s->period.name.streq(drop->name);
|
||||
}
|
||||
|
||||
if (drop)
|
||||
{
|
||||
drop_period= true;
|
||||
drop_it.remove();
|
||||
}
|
||||
else if (create_info->period_info.is_set() && table->s->period.name)
|
||||
{
|
||||
my_error(ER_MORE_THAN_ONE_PERIOD, MYF(0));
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
Field *s= table->s->period.start_field(table->s);
|
||||
Field *e= table->s->period.end_field(table->s);
|
||||
create_info->period_info.set_period(s->field_name, e->field_name);
|
||||
create_info->period_info.name= table->s->period.name;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all table level constraints which are not in the drop list */
|
||||
if (table->s->table_check_constraints)
|
||||
{
|
||||
@ -8366,6 +8434,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
{
|
||||
Virtual_column_info *check= table->check_constraints[i];
|
||||
Alter_drop *drop;
|
||||
bool keep= true;
|
||||
drop_it.rewind();
|
||||
while ((drop=drop_it++))
|
||||
{
|
||||
@ -8373,17 +8442,39 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
!my_strcasecmp(system_charset_info, check->name.str, drop->name))
|
||||
{
|
||||
drop_it.remove();
|
||||
keep= false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (share->period.constr_name.streq(check->name.str))
|
||||
{
|
||||
if (!drop_period && !keep)
|
||||
{
|
||||
my_error(ER_PERIOD_CONSTRAINT_DROP, MYF(0), check->name.str,
|
||||
share->period.name.str);
|
||||
goto err;
|
||||
}
|
||||
keep= keep && !drop_period;
|
||||
|
||||
DBUG_ASSERT(create_info->period_info.constr == NULL || drop_period);
|
||||
|
||||
if (keep)
|
||||
{
|
||||
Item *expr_copy= check->expr->get_copy(thd);
|
||||
check= new Virtual_column_info();
|
||||
check->expr= expr_copy;
|
||||
create_info->period_info.constr= check;
|
||||
}
|
||||
}
|
||||
/* see if the constraint depends on *only* on dropped fields */
|
||||
if (!drop && dropped_fields)
|
||||
if (keep && dropped_fields)
|
||||
{
|
||||
table->default_column_bitmaps();
|
||||
bitmap_clear_all(table->read_set);
|
||||
check->expr->walk(&Item::register_field_in_read_map, 1, 0);
|
||||
if (bitmap_is_subset(table->read_set, dropped_fields))
|
||||
drop= (Alter_drop*)1;
|
||||
keep= false;
|
||||
else if (bitmap_is_overlapping(dropped_fields, table->read_set))
|
||||
{
|
||||
bitmap_intersect(table->read_set, dropped_fields);
|
||||
@ -8393,7 +8484,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (!drop)
|
||||
if (keep)
|
||||
{
|
||||
if (alter_info->flags & ALTER_RENAME_COLUMN)
|
||||
{
|
||||
@ -8417,8 +8508,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
|
||||
case Alter_drop::KEY:
|
||||
case Alter_drop::COLUMN:
|
||||
case Alter_drop::CHECK_CONSTRAINT:
|
||||
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
|
||||
alter_info->drop_list.head()->name);
|
||||
case Alter_drop::PERIOD:
|
||||
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
|
||||
alter_info->drop_list.head()->name);
|
||||
goto err;
|
||||
case Alter_drop::FOREIGN_KEY:
|
||||
// Leave the DROP FOREIGN KEY names in the alter_info->drop_list.
|
||||
@ -9341,7 +9433,7 @@ do_continue:;
|
||||
}
|
||||
}
|
||||
|
||||
handle_if_exists_options(thd, table, alter_info);
|
||||
handle_if_exists_options(thd, table, alter_info, &create_info->period_info);
|
||||
|
||||
/*
|
||||
Look if we have to do anything at all.
|
||||
@ -9423,6 +9515,10 @@ do_continue:;
|
||||
|
||||
set_table_default_charset(thd, create_info, &alter_ctx.db);
|
||||
|
||||
if (create_info->check_period_fields(thd, alter_info)
|
||||
|| create_info->fix_period_fields(thd, alter_info))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
if (!opt_explicit_defaults_for_timestamp)
|
||||
promote_first_timestamp_column(&alter_info->create_list);
|
||||
|
||||
|
@ -2066,6 +2066,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
key_using_alg
|
||||
part_column_list
|
||||
period_for_system_time
|
||||
period_for_application_time
|
||||
server_def server_options_list server_option
|
||||
definer_opt no_definer definer get_diagnostics
|
||||
parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
|
||||
@ -6538,6 +6539,7 @@ field_list_item:
|
||||
| key_def
|
||||
| constraint_def
|
||||
| period_for_system_time
|
||||
| PERIOD_SYM period_for_application_time { }
|
||||
;
|
||||
|
||||
column_def:
|
||||
@ -6645,9 +6647,12 @@ period_for_system_time:
|
||||
Vers_parse_info &info= Lex->vers_get_info();
|
||||
info.set_period($4, $6);
|
||||
}
|
||||
| PERIOD_SYM FOR_SYM ident '(' ident ',' ident ')'
|
||||
;
|
||||
|
||||
period_for_application_time:
|
||||
FOR_SYM ident '(' ident ',' ident ')'
|
||||
{
|
||||
if (Lex->add_period($3, $5, $7))
|
||||
if (Lex->add_period($2, $4, $6))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
@ -8324,6 +8329,13 @@ alter_list_item:
|
||||
{
|
||||
Lex->alter_info.flags|= ALTER_ADD_PERIOD;
|
||||
}
|
||||
| ADD
|
||||
PERIOD_SYM opt_if_not_exists_table_element period_for_application_time
|
||||
{
|
||||
Table_period_info &period= Lex->create_info.period_info;
|
||||
period.create_if_not_exists= Lex->check_exists;
|
||||
Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT;
|
||||
}
|
||||
| add_column '(' create_field_list ')'
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
@ -8493,6 +8505,14 @@ alter_list_item:
|
||||
{
|
||||
Lex->alter_info.flags|= ALTER_DROP_PERIOD;
|
||||
}
|
||||
| DROP PERIOD_SYM opt_if_exists_table_element FOR_SYM ident
|
||||
{
|
||||
Alter_drop *ad= new Alter_drop(Alter_drop::PERIOD, $5.str, $3);
|
||||
if (unlikely(ad == NULL))
|
||||
MYSQL_YYABORT;
|
||||
Lex->alter_info.drop_list.push_back(ad, thd->mem_root);
|
||||
Lex->alter_info.flags|= ALTER_DROP_CHECK_CONSTRAINT;
|
||||
}
|
||||
;
|
||||
|
||||
opt_index_lock_algorithm:
|
||||
|
19
sql/table.cc
19
sql/table.cc
@ -2028,13 +2028,26 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
|
||||
|
||||
if (extra2.application_period.str)
|
||||
{
|
||||
period.name.length= extra2.application_period.length - 2 * frm_fieldno_size;
|
||||
const uchar *name_pos= extra2.application_period.str + frm_ident_len_size;
|
||||
period.name.length= uint2korr(extra2.application_period.str);
|
||||
period.name.str= strmake_root(&mem_root,
|
||||
(char*)extra2.application_period.str,
|
||||
(char*)name_pos,
|
||||
period.name.length);
|
||||
const uchar *field_pos= extra2.application_period.str + period.name.length;
|
||||
|
||||
const uchar *constr_pos= name_pos + period.name.length + frm_ident_len_size;
|
||||
period.constr_name.length= uint2korr(name_pos + period.name.length);
|
||||
period.constr_name.str= strmake_root(&mem_root,
|
||||
(char*)constr_pos,
|
||||
period.constr_name.length);
|
||||
|
||||
const uchar *field_pos= constr_pos + period.constr_name.length;
|
||||
if (init_period_from_extra2(period, field_pos))
|
||||
goto err;
|
||||
|
||||
if (period.name.length + period.constr_name.length
|
||||
+ 2 * frm_ident_len_size + 2 * frm_fieldno_size
|
||||
!= extra2.application_period.length)
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
|
||||
|
@ -774,6 +774,7 @@ struct TABLE_SHARE
|
||||
uint16 start_fieldno;
|
||||
uint16 end_fieldno;
|
||||
Lex_ident name;
|
||||
Lex_ident constr_name;
|
||||
Field *start_field(TABLE_SHARE *s) const
|
||||
{
|
||||
return s->field[start_fieldno];
|
||||
@ -1782,6 +1783,8 @@ class IS_table_read_plan;
|
||||
|
||||
/** number of bytes used by field positional indexes in frm */
|
||||
constexpr uint frm_fieldno_size= 2;
|
||||
/** number of bytes used by identifier length in frm */
|
||||
constexpr uint frm_ident_len_size= 2;
|
||||
|
||||
class select_unit;
|
||||
class TMP_TABLE_PARAM;
|
||||
|
@ -143,6 +143,14 @@ bool has_extra2_field_flags(List<Create_field> &create_fields)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
uchar* store_str(uchar *buf, const Lex_ident &str)
|
||||
{
|
||||
int2store(buf, str.length);
|
||||
memcpy(buf + frm_ident_len_size, str.str, str.length);
|
||||
return buf + str.length + frm_ident_len_size;
|
||||
}
|
||||
|
||||
/**
|
||||
Create a frm (table definition) file
|
||||
|
||||
@ -170,8 +178,11 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING *table,
|
||||
ulong data_offset;
|
||||
uint options_len;
|
||||
uint gis_extra2_len= 0;
|
||||
uint period_info_len= create_info->period_info.name.length
|
||||
+ 2 * frm_fieldno_size;
|
||||
size_t period_info_len= create_info->period_info.name
|
||||
? create_info->period_info.name.length
|
||||
+ create_info->period_info.constr->name.length
|
||||
+ 2 * frm_ident_len_size + 2 * frm_fieldno_size
|
||||
: 0;
|
||||
uchar fileinfo[FRM_HEADER_SIZE],forminfo[FRM_FORMINFO_SIZE];
|
||||
const partition_info *part_info= IF_PARTITIONING(thd->work_part_info, 0);
|
||||
bool error;
|
||||
@ -351,14 +362,12 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING *table,
|
||||
#endif /*HAVE_SPATIAL*/
|
||||
|
||||
// PERIOD
|
||||
if (create_info->period_info.name)
|
||||
if (create_info->period_info.is_set())
|
||||
{
|
||||
*pos++= EXTRA2_APPLICATION_TIME_PERIOD;
|
||||
|
||||
Lex_ident &period_name= create_info->period_info.name;
|
||||
pos= extra2_write_len(pos, period_info_len);
|
||||
memcpy(pos, period_name.str, period_name.length);
|
||||
pos+= period_name.length;
|
||||
pos= store_str(pos, create_info->period_info.name);
|
||||
pos= store_str(pos, create_info->period_info.constr->name);
|
||||
|
||||
int2store(pos, get_fieldno_by_name(create_info, create_fields,
|
||||
create_info->period_info.period.start));
|
||||
|
Loading…
x
Reference in New Issue
Block a user