diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index e445842192f..b0255c7457b 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2033,3 +2033,86 @@ Sys_end INT GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) ) WITH SYSTEM VERSIONING; ERROR HY000: System end field must be of type TIMESTAMP +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `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 t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) 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 t1; +CREATE TABLE t1 ( +A INT, +B INT WITHOUT SYSTEM VERSIONING +); +ERROR HY000: Every field specified unversioned in versioned table +CREATE TABLE t1 ( +A INT, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `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 t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT WITHOUT SYSTEM VERSIONING +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `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 t1; +CREATE TABLE t1 ( +A INT WITH SYSTEM VERSIONING, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `A` int(11) DEFAULT NULL, + `B` int(11) DEFAULT NULL WITHOUT SYSTEM VERSIONING, + `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 t1; +CREATE TABLE t1 ( +A INT WITHOUT SYSTEM VERSIONING +); +ERROR HY000: Every field specified unversioned in versioned table +CREATE TABLE t1 ( +A INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +ERROR HY000: Every field specified unversioned in versioned table diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index d244afa03e3..bb68029a490 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -1227,3 +1227,35 @@ No A B C D 2 1 1 1 1 3 1 1 1 1 drop procedure verify_vtq; +CREATE TABLE t1 ( +id BIGINT PRIMARY KEY, +name VARCHAR(128) WITH SYSTEM VERSIONING, +salary BIGINT +); +INSERT INTO t1 VALUES (1, "Jeremy", 3000); +CREATE TABLE t2 ( +id BIGINT PRIMARY KEY, +name VARCHAR(128) WITH SYSTEM VERSIONING, +salary BIGINT +); +INSERT INTO t2 VALUES (1, "Jeremy", 4000); +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; +SELECT @tmp1 < sys_trx_start, name FROM t1; +@tmp1 < sys_trx_start name +1 Jerry +SELECT @tmp2 < sys_trx_start, name FROM t2; +@tmp2 < sys_trx_start name +1 Jerry +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; +SELECT @tmp1 = sys_trx_start, salary FROM t1; +@tmp1 = sys_trx_start salary +1 2500 +SELECT @tmp2 = sys_trx_start, salary FROM t2; +@tmp2 = sys_trx_start salary +1 2500 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 6bce00b8257..e0e58985adc 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -845,3 +845,20 @@ No A B C D 1 1 1 1 1 2 1 1 1 1 drop procedure verify_vtq; +CREATE TABLE t1 ( +id BIGINT PRIMARY KEY, +A INT, +B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +INSERT INTO t1 VALUES(1, 1, 1); +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET A=11, B=11 WHERE id=1; +SELECT @tmp1 < sys_trx_start, A, B FROM t1; +@tmp1 < sys_trx_start A B +1 11 11 +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET B=1 WHERE id=1; +SELECT @tmp1 = sys_trx_start, B FROM t1; +@tmp1 = sys_trx_start B +1 1 +DROP TABLE t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 5732fbbe03d..ebdd3794176 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1887,3 +1887,54 @@ create table t1 ( Sys_end INT GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME (Sys_start, Sys_end) ) WITH SYSTEM VERSIONING; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT +); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT, + B INT WITHOUT SYSTEM VERSIONING +); + +CREATE TABLE t1 ( + A INT, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT WITHOUT SYSTEM VERSIONING +); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + A INT WITH SYSTEM VERSIONING, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT WITHOUT SYSTEM VERSIONING +); + +--error ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE +CREATE TABLE t1 ( + A INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 325d65e5872..3e2b9ceeaea 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -1119,3 +1119,32 @@ delimiter ;~~ call verify_vtq; drop procedure verify_vtq; + +CREATE TABLE t1 ( + id BIGINT PRIMARY KEY, + name VARCHAR(128) WITH SYSTEM VERSIONING, + salary BIGINT +); +INSERT INTO t1 VALUES (1, "Jeremy", 3000); + +CREATE TABLE t2 ( + id BIGINT PRIMARY KEY, + name VARCHAR(128) WITH SYSTEM VERSIONING, + salary BIGINT +); +INSERT INTO t2 VALUES (1, "Jeremy", 4000); + +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.name="Jerry", t2.name="Jerry" WHERE t1.id=t2.id AND t1.name="Jeremy"; +SELECT @tmp1 < sys_trx_start, name FROM t1; +SELECT @tmp2 < sys_trx_start, name FROM t2; + +SELECT sys_trx_start INTO @tmp1 FROM t1; +SELECT sys_trx_start INTO @tmp2 FROM t2; +UPDATE t1, t2 SET t1.salary=2500, t2.salary=2500 WHERE t1.id=t2.id AND t1.name="Jerry"; +SELECT @tmp1 = sys_trx_start, salary FROM t1; +SELECT @tmp2 = sys_trx_start, salary FROM t2; + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 784c563fbf2..41d59199e47 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -726,3 +726,21 @@ delimiter ;~~ call verify_vtq; drop procedure verify_vtq; + +CREATE TABLE t1 ( + id BIGINT PRIMARY KEY, + A INT, + B INT WITHOUT SYSTEM VERSIONING +) WITH SYSTEM VERSIONING; + +INSERT INTO t1 VALUES(1, 1, 1); + +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET A=11, B=11 WHERE id=1; +SELECT @tmp1 < sys_trx_start, A, B FROM t1; + +SELECT sys_trx_start INTO @tmp1 FROM t1; +UPDATE t1 SET B=1 WHERE id=1; +SELECT @tmp1 = sys_trx_start, B FROM t1; + +DROP TABLE t1; diff --git a/sql/field.h b/sql/field.h index 4b6607fa099..bf4f8b5ce5c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3872,6 +3872,13 @@ class Column_definition: public Sql_alloc } } public: + enum enum_column_versioning + { + VERSIONING_NOT_SET, + WITH_VERSIONING, + WITHOUT_VERSIONING + }; + const char *field_name; LEX_STRING comment; // Comment for field Item *on_update; // ON UPDATE NOW() @@ -3907,6 +3914,8 @@ public: *default_value, // Default value *check_constraint; // Check constraint + enum_column_versioning versioning; + Column_definition(): comment(null_lex_str), on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0), @@ -3914,7 +3923,8 @@ public: interval(0), charset(&my_charset_bin), srid(0), geom_type(Field::GEOM_GEOMETRY), option_list(NULL), pack_flag(0), - vcol_info(0), default_value(0), check_constraint(0) + vcol_info(0), default_value(0), check_constraint(0), + versioning(VERSIONING_NOT_SET) { interval_list.empty(); } @@ -4276,6 +4286,7 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U +#define FIELDFLAG_WITHOUT_SYSTEM_VERSIONING 8192U #define FIELDFLAG_NO_DEFAULT 16384U /* sql */ #define FIELDFLAG_MAYBE_NULL 32768U // sql #define FIELDFLAG_HEX_ESCAPE 0x10000U @@ -4302,5 +4313,6 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) +#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) #endif /* FIELD_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 0c2dea8b00e..174d15194a0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6582,12 +6582,35 @@ static bool create_sys_trx_field_if_missing(THD *thd, const char *field_name, return false; } -bool System_versioning_info::add_implicit_fields(THD *thd, +bool System_versioning_info::add_versioning_info(THD *thd, Alter_info *alter_info) { - if (!declared_system_versioning) + DBUG_ASSERT(versioned()); + + if (!declared_system_versioning && !has_versioned_fields) return false; + bool without_system_versioning_by_default= !declared_system_versioning; + List_iterator it(alter_info->create_list); + while (Create_field *f= it++) + { + const char *name= f->field_name; + size_t len= strlen(name); + if (generated_as_row.start && + !strncmp(name, generated_as_row.start->c_ptr(), len)) + continue; + if (generated_as_row.end && + !strncmp(name, generated_as_row.end->c_ptr(), len)) + continue; + + if (f->versioning == Column_definition::VERSIONING_NOT_SET && + without_system_versioning_by_default) + f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + + else if (f->versioning == Column_definition::WITHOUT_VERSIONING) + f->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + } + // 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) @@ -6602,3 +6625,99 @@ bool System_versioning_info::add_implicit_fields(THD *thd, create_string(thd->mem_root, &period_for_system_time.end, "sys_trx_end"); } + +bool System_versioning_info::check(THD *thd, Alter_info *alter_info) +{ + if (!versioned()) + return false; + + if (add_versioning_info(thd, alter_info)) + return true; + + bool r= false; + + { + int not_set= 0; + int with= 0; + List_iterator it(alter_info->create_list); + while (const Create_field *f= it++) + { + const char *name= f->field_name; + size_t len= strlen(name); + if (generated_as_row.start && + !strncmp(name, generated_as_row.start->c_ptr(), len)) + continue; + if (generated_as_row.end && + !strncmp(name, generated_as_row.end->c_ptr(), len)) + continue; + + if (f->versioning == Column_definition::VERSIONING_NOT_SET) + not_set++; + else if (f->versioning == Column_definition::WITH_VERSIONING) + with++; + } + + bool table_with_system_versioning= + declared_system_versioning || generated_as_row.start || + generated_as_row.end || period_for_system_time.start || + period_for_system_time.end; + + if ((table_with_system_versioning && not_set == 0 && with == 0) || + (!table_with_system_versioning && with == 0)) + { + r= true; + my_error(ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE, MYF(0)); + } + } + + if (!declared_system_versioning && !has_versioned_fields) + { + r= true; + my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); + } + + if (!generated_as_row.start) + { + r= true; + my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); + } + + if (!generated_as_row.end) + { + r= true; + my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); + } + + if (!period_for_system_time.start || !period_for_system_time.end) + { + r= true; + my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); + } + + if (!r) + { + if (my_strcasecmp(system_charset_info, generated_as_row.start->c_ptr(), + period_for_system_time.start->c_ptr())) + { + r= true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); + } + + if (my_strcasecmp(system_charset_info, generated_as_row.end->c_ptr(), + period_for_system_time.end->c_ptr())) + { + r= true; + my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); + } + } + + return r; // false means no error +} + +bool System_versioning_info::versioned() const +{ + return has_versioned_fields || has_unversioned_fields || + declared_system_versioning || period_for_system_time.start || + period_for_system_time.end || generated_as_row.start || + generated_as_row.end; +} diff --git a/sql/handler.h b/sql/handler.h index 8b7b6f516a1..698703f89ff 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1671,6 +1671,14 @@ struct Schema_specification_st struct System_versioning_info { + System_versioning_info() : + period_for_system_time({NULL, NULL}), + generated_as_row({NULL, NULL}), + declared_system_versioning(false), + has_versioned_fields(false), + has_unversioned_fields(false) + {} + struct { String *start, *end; @@ -1693,13 +1701,28 @@ struct System_versioning_info } /** Returns true on failure */ - bool add_implicit_fields(THD *thd, Alter_info *alter_info); + bool add_versioning_info(THD *thd, Alter_info *alter_info); + + /** Returns true on failure */ + bool check(THD *thd, Alter_info *alter_info); + + /** Returns true if table is versioned */ + bool versioned() const; /** User has added 'WITH SYSTEM VERSIONING' to table definition */ - bool declared_system_versioning; + bool declared_system_versioning : 1; - /** Table described by this structure have enabled system versioning */ - bool versioned; + /** + At least one field was specified 'WITH SYSTEM VERSIONING'. Useful for + error handling. + */ + bool has_versioned_fields : 1; + + /** + At least one field was specified 'WITHOUT SYSTEM VERSIONING'. Useful for + error handling. + */ + bool has_unversioned_fields : 1; }; /** @@ -1791,7 +1814,7 @@ struct Table_scope_and_contents_source_st bool versioned() const { - return system_versioning_info.versioned; + return system_versioning_info.versioned(); } const System_versioning_info *get_system_versioning_info() const { diff --git a/sql/lex.h b/sql/lex.h index da5a288be99..dff6624518a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -703,6 +703,7 @@ static SYMBOL symbols[] = { { "WHILE", SYM(WHILE_SYM)}, { "WINDOW", SYM(WINDOW_SYM)}, { "WITH", SYM(WITH)}, + { "WITHOUT", SYM(WITHOUT)}, { "WORK", SYM(WORK_SYM)}, { "WRAPPER", SYM(WRAPPER_SYM)}, { "WRITE", SYM(WRITE_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f3859b5ba4a..167be4d10fc 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7537,3 +7537,6 @@ ER_SYS_START_FIELD_MUST_BE_BIGINT ER_SYS_END_FIELD_MUST_BE_BIGINT eng "System end field must be of type BIGINT UNSIGNED" + +ER_NO_VERSIONED_FIELDS_IN_VERSIONED_TABLE + eng "Every field specified unversioned in versioned table" diff --git a/sql/sql_class.h b/sql/sql_class.h index 1b920b23a2d..49f62f9ea4e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5533,6 +5533,8 @@ class multi_update :public select_result_interceptor // For System Versioning (may need to insert new fields to a table). ha_rows updated_sys_ver; + bool has_vers_fields; + public: multi_update(THD *thd_arg, TABLE_LIST *ut, List *leaves_list, List *fields, List *values, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9bae9ecc658..6b75c030374 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -138,7 +138,6 @@ static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state); static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables); static bool execute_show_status(THD *, TABLE_LIST *); static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); -static bool check_system_versioning(Table_scope_and_contents_source_st *); const char *any_db="*any*"; // Special symbol for check_access @@ -3856,11 +3855,7 @@ 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)) + if (create_info.system_versioning_info.check(thd, &alter_info)) goto end_with_restore_list; /* Check privileges */ @@ -7326,66 +7321,6 @@ bool check_fk_parent_table_access(THD *thd, } - -/**************************************************************************** - Checks related to system versioning -****************************************************************************/ - -static bool check_system_versioning(Table_scope_and_contents_source_st *create_info) -{ - const System_versioning_info *versioning_info = &create_info->system_versioning_info; - - if (!versioning_info->versioned) - return false; - - bool r = false; - - if (!versioning_info->declared_system_versioning) - { - r = true; - my_error(ER_MISSING_WITH_SYSTEM_VERSIONING, MYF(0)); - } - - if (!versioning_info->generated_as_row.start) - { - r = true; - my_error(ER_SYS_START_NOT_SPECIFIED, MYF(0)); - } - - if (!versioning_info->generated_as_row.end) - { - r = true; - my_error(ER_SYS_END_NOT_SPECIFIED, MYF(0)); - } - - if (!versioning_info->period_for_system_time.start || !versioning_info->period_for_system_time.end) - { - r = true; - my_error(ER_MISSING_PERIOD_FOR_SYSTEM_TIME, MYF(0)); - } - - if (!r) - { - if (my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.start->c_ptr(), - versioning_info->period_for_system_time.start->c_ptr())) - { - r = true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_START_COLUMN, MYF(0)); - } - - if (my_strcasecmp(system_charset_info, - versioning_info->generated_as_row.end->c_ptr(), - versioning_info->period_for_system_time.end->c_ptr())) - { - r = true; - my_error(ER_PERIOD_FOR_SYSTEM_TIME_CONTAINS_WRONG_END_COLUMN, MYF(0)); - } - } - - return r; // false means no error -} - /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 084e98b143f..cc7f2b0a017 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2133,6 +2133,11 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" GENERATED AS ROW END")); } + if (field->is_versioning_disabled()) + { + packet->append(STRING_WITH_LEN(" WITHOUT SYSTEM VERSIONING")); + } + if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false)) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 620f580d688..8b62c71733c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2989,6 +2989,8 @@ bool Column_definition::prepare_create_field(uint *blob_columns, pack_flag|= FIELDFLAG_MAYBE_NULL; if (flags & NO_DEFAULT_VALUE_FLAG) pack_flag|= FIELDFLAG_NO_DEFAULT; + if (flags & WITHOUT_SYSTEM_VERSIONING_FLAG) + pack_flag|= FIELDFLAG_WITHOUT_SYSTEM_VERSIONING; DBUG_RETURN(false); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index acbbf559c63..419ccc1bc94 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -155,6 +155,17 @@ static bool check_fields(THD *thd, List &items) return FALSE; } +static bool check_has_vers_fields(List &items) +{ + List_iterator it(items); + while (Item *item= it++) + { + if (Item_field *item_field= item->field_for_view_update()) + if (!(item_field->field->flags & WITHOUT_SYSTEM_VERSIONING_FLAG)) + return true; + } + return false; +} /** Re-read record if more columns are needed for error message. @@ -355,6 +366,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); } + bool has_vers_fields= check_has_vers_fields(fields); if (check_key_in_view(thd, table_list)) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); @@ -763,7 +775,7 @@ int mysql_update(THD *thd, TRG_EVENT_UPDATE)) break; /* purecov: inspected */ - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); found++; @@ -835,7 +847,7 @@ int mysql_update(THD *thd, { updated++; - if (table->versioned()) + if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { @@ -1671,6 +1683,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, transactional_tables(0), ignore(ignore_arg), error_handled(0), prepared(0), updated_sys_ver(0) { + has_vers_fields= check_has_vers_fields(*field_list); } @@ -2176,7 +2189,7 @@ int multi_update::send_data(List ¬_used_values) if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); if ((error= cur_table->view_check_option(thd, ignore)) != @@ -2226,7 +2239,7 @@ int multi_update::send_data(List ¬_used_values) error= 0; updated--; } - else if (table->versioned()) + else if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { @@ -2511,7 +2524,7 @@ int multi_update::do_updates() goto err2; } } - if (table->versioned_by_sql()) + if (has_vers_fields && table->versioned_by_sql()) table->vers_update_fields(); if ((local_error=table->file->ha_update_row(table->record[1], @@ -2529,7 +2542,7 @@ int multi_update::do_updates() { updated++; - if (table->versioned()) + if (has_vers_fields && table->versioned()) { if (table->versioned_by_sql()) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 05c05c3e144..9b11ac0cfe9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1572,6 +1572,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WINDOW_SYM %token WHILE_SYM %token WITH /* SQL-2003-R */ +%token WITHOUT /* SQL-2003-R */ %token WITH_CUBE_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */ %token WORK_SYM /* SQL-2003-N */ @@ -5852,7 +5853,7 @@ create_table_option: { System_versioning_info &info= Lex->vers_get_info(); info.declared_system_versioning= true; - info.versioned= true; + Lex->create_info.options|= HA_VERSIONED_TABLE; } ; @@ -6064,7 +6065,6 @@ period_for_system_time: MYSQL_YYABORT; } info.set_period_for_system_time($4, $6); - info.versioned= true; } ; @@ -6165,7 +6165,6 @@ field_def: | opt_generated_always AS ROW_SYM start_or_end { 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) @@ -6667,6 +6666,16 @@ serial_attribute: new (thd->mem_root) engine_option_value($1, &Lex->last_field->option_list, &Lex->option_list_last); } + | WITH SYSTEM VERSIONING + { + Lex->last_field->versioning = Column_definition::WITH_VERSIONING; + Lex->create_info.system_versioning_info.has_versioned_fields= true; + } + | WITHOUT SYSTEM VERSIONING + { + Lex->last_field->versioning = Column_definition::WITHOUT_VERSIONING; + Lex->create_info.system_versioning_info.has_unversioned_fields= true; + } ; diff --git a/sql/table.cc b/sql/table.cc index 80a7046be1a..3a75fbe8e48 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2017,6 +2017,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (f_no_default(pack_flag)) reg_field->flags|= NO_DEFAULT_VALUE_FLAG; + if (f_without_system_versioning(pack_flag)) + reg_field->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + if (reg_field->unireg_check == Field::NEXT_NUMBER) share->found_next_number_field= field_ptr;