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:
Nikita Malyavin 2019-02-04 09:37:39 +10:00 committed by Sergei Golubchik
parent b2bd52290a
commit 6294516a56
17 changed files with 533 additions and 53 deletions

View 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;

View File

@ -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;

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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"

View File

@ -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";
}
};

View File

@ -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");

View File

@ -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;
}

View File

@ -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 "));

View File

@ -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);

View File

@ -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:

View File

@ -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++)

View File

@ -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;

View File

@ -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));