From d8c8d7b9462e3a1c07c97a4cc8e0cb3e5c2ccbae Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Wed, 21 Sep 2016 23:30:52 +0300 Subject: [PATCH] added implicitly generated fields in versioned tables support and refactored code a bit --- mysql-test/r/create.result | 13 ++++++++++ mysql-test/t/create.test | 8 ++++++ sql/handler.cc | 50 ++++++++++++++++++++++++++++++++++++++ sql/handler.h | 13 ++++++++-- sql/sql_lex.h | 5 ++-- sql/sql_parse.cc | 11 ++++++--- sql/sql_yacc.yy | 36 ++++++++++++--------------- 7 files changed, 107 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 941ba2837d2..e445842192f 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1949,6 +1949,19 @@ t1 CREATE TABLE `t1` ( PERIOD FOR SYSTEM_TIME (`Sys_start`, `Sys_end`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING drop table if exists t1; +# Versioning fields are set implicitly. +create table t1 ( +XNo INT UNSIGNED +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `XNo` int(10) unsigned DEFAULT NULL, + `sys_trx_start` timestamp(6) NULL GENERATED AS ROW START, + `sys_trx_end` timestamp(6) NULL GENERATED AS ROW END, + PERIOD FOR SYSTEM_TIME (`sys_trx_start`, `sys_trx_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +drop table if exists t1; create table t1 ( XNo INT UNSIGNED, Sys_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START, diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 5e5c5008d8e..5732fbbe03d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1799,6 +1799,14 @@ SHOW CREATE TABLE t1; drop table if exists t1; +--echo # Versioning fields are set implicitly. +create table t1 ( + XNo INT UNSIGNED +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; + +drop table if exists t1; + --error ER_SYS_START_MORE_THAN_ONCE create table t1 ( XNo INT UNSIGNED, diff --git a/sql/handler.cc b/sql/handler.cc index 5d0ec99e978..b27dc224c48 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6552,3 +6552,53 @@ int del_global_index_stat(THD *thd, TABLE* table, KEY* key_info) mysql_mutex_unlock(&LOCK_global_index_stats); DBUG_RETURN(res); } + +static bool create_string(MEM_ROOT *mem_root, String **s, const char *value) +{ + *s= new (mem_root) String(value, system_charset_info); + return *s == NULL; +} + +static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, + Alter_info *alter_info, String **s) +{ + Create_field *f= new (thd->mem_root) Create_field(); + if (!f) + return true; + + f->field_name= field_name; + f->charset= system_charset_info; + f->sql_type= MYSQL_TYPE_TIMESTAMP; + f->length= 6; + f->decimals= 0; + + if (f->check(thd)) + return true; + + if (create_string(thd->mem_root, s, field_name)) + return true; + + alter_info->create_list.push_back(f); + return false; +} + +bool System_versioning_info::add_implicit_fields(THD *thd, + Alter_info *alter_info) +{ + if (!declared_system_versioning) + return false; + + // If user specified some of these he must specify the others too. Do nothing. + if (generated_as_row.start || generated_as_row.end || + period_for_system_time.start || period_for_system_time.end) + return false; + + return create_sys_trx_field_if_missing(thd, "sys_trx_start", alter_info, + &generated_as_row.start) || + create_sys_trx_field_if_missing(thd, "sys_trx_end", alter_info, + &generated_as_row.end) || + create_string(thd->mem_root, &period_for_system_time.start, + "sys_trx_start") || + create_string(thd->mem_root, &period_for_system_time.end, + "sys_trx_end"); +} diff --git a/sql/handler.h b/sql/handler.h index 2b911cd94c5..e88579f9d9d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1683,6 +1683,9 @@ struct System_versioning_info set_period_for_system_time(NULL, NULL); } + /** Returns true on failure */ + bool add_implicit_fields(THD *thd, Alter_info *alter_info); + /** User has added 'WITH SYSTEM VERSIONING' to table definition */ bool declared_system_versioning; @@ -1777,11 +1780,17 @@ struct Table_scope_and_contents_source_st : ha_default_handlerton(thd); } - bool versioned() + bool versioned() const { return system_versioning_info.versioned; } - const System_versioning_info *get_system_versioning_info() + const System_versioning_info *get_system_versioning_info() const + { + if (!versioned()) + return NULL; + return &system_versioning_info; + } + System_versioning_info *get_system_versioning_info() { if (!versioned()) return NULL; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a7fe77ca5a7..9b625d3b7b3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3561,10 +3561,9 @@ public: bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); - System_versioning_info *vers_get_info() + System_versioning_info &vers_get_info() { - create_info.system_versioning_info.versioned = true; - return &create_info.system_versioning_info; + return create_info.system_versioning_info; } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5484467509a..9bae9ecc658 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3849,10 +3849,6 @@ mysql_execute_command(THD *thd) copy. */ Alter_info alter_info(lex->alter_info, thd->mem_root); - - if (check_system_versioning(&create_info)) - goto end_with_restore_list; - if (thd->is_fatal_error) { /* If out of memory when creating a copy of alter_info. */ @@ -3860,6 +3856,13 @@ mysql_execute_command(THD *thd) goto end_with_restore_list; } + if (System_versioning_info *info= create_info.get_system_versioning_info()) + if (info->add_implicit_fields(thd, &alter_info)) + goto end_with_restore_list; + + if (check_system_versioning(&create_info)) + goto end_with_restore_list; + /* Check privileges */ if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b09055e323..7e8ef6ec8fb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5852,10 +5852,9 @@ create_table_option: } | WITH SYSTEM VERSIONING { - System_versioning_info *info = Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; - info->declared_system_versioning = true; + System_versioning_info &info= Lex->vers_get_info(); + info.declared_system_versioning= true; + info.versioned= true; } ; @@ -6060,15 +6059,14 @@ period_for_system_time: // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' period_for_system_time_column_id ',' period_for_system_time_column_id ')' { - System_versioning_info *info = Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; + System_versioning_info &info= Lex->vers_get_info(); if (!my_strcasecmp(system_charset_info, $4->c_ptr(), $6->c_ptr())) { my_error(ER_SYS_START_AND_SYS_END_SAME, MYF(0), $4->c_ptr()); MYSQL_YYABORT; } - info->set_period_for_system_time($4, $6); + info.set_period_for_system_time($4, $6); + info.versioned= true; } ; @@ -6168,26 +6166,24 @@ field_def: vcol_opt_specifier vcol_opt_attribute | opt_generated_always AS ROW_SYM start_or_end { - System_versioning_info *info = - Lex->vers_get_info(); - if (!info) - MYSQL_YYABORT; - String *field_name = new (thd->mem_root) + System_versioning_info &info= Lex->vers_get_info(); + info.versioned= true; + String *field_name= new (thd->mem_root) String((const char*)Lex->last_field->field_name, system_charset_info); if (!field_name) MYSQL_YYABORT; - String **p = NULL; - int err_nr = 0; + String **p= NULL; + int err_nr= 0; switch ($4) { case 1: - p = &info->generated_as_row.start; - err_nr = ER_SYS_START_MORE_THAN_ONCE; + p= &info.generated_as_row.start; + err_nr= ER_SYS_START_MORE_THAN_ONCE; break; case 0: - p = &info->generated_as_row.end; - err_nr = ER_SYS_END_MORE_THAN_ONCE; + p= &info.generated_as_row.end; + err_nr= ER_SYS_END_MORE_THAN_ONCE; break; default: /* Not Reachable */ @@ -6199,7 +6195,7 @@ field_def: my_error(err_nr, MYF(0), field_name->c_ptr()); MYSQL_YYABORT; } - *p = field_name; + *p= field_name; } ;