diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 4 | ||||
-rw-r--r-- | sql/handler.cc | 109 | ||||
-rw-r--r-- | sql/handler.h | 72 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 8 | ||||
-rw-r--r-- | sql/sql_lex.h | 21 | ||||
-rw-r--r-- | sql/sql_parse.cc | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 33 | ||||
-rw-r--r-- | sql/sql_table.cc | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 7 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 7 | ||||
-rw-r--r-- | sql/table.cc | 277 | ||||
-rw-r--r-- | sql/table.h | 35 | ||||
-rw-r--r-- | sql/unireg.cc | 47 | ||||
-rw-r--r-- | sql/unireg.h | 1 |
14 files changed, 446 insertions, 183 deletions
diff --git a/sql/field.h b/sql/field.h index 30098afe953..a348e9ec480 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4560,6 +4560,8 @@ public: enum_column_versioning versioning; + Table_period_info *period; + Column_definition() :Type_handler_hybrid_field_type(&type_handler_null), compression_method_ptr(0), @@ -4568,7 +4570,7 @@ public: flags(0), pack_length(0), key_length(0), option_list(NULL), vcol_info(0), default_value(0), check_constraint(0), - versioning(VERSIONING_NOT_SET) + versioning(VERSIONING_NOT_SET), period(NULL) { interval_list.empty(); } diff --git a/sql/handler.cc b/sql/handler.cc index bc183837903..9150b055313 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -7183,8 +7183,8 @@ bool Vers_parse_info::fix_implicit(THD *thd, Alter_info *alter_info) alter_info->flags|= ALTER_PARSER_ADD_COLUMN; - system_time= start_end_t(default_start, default_end); - as_row= system_time; + period= start_end_t(default_start, default_end); + as_row= period; if (vers_create_sys_field(thd, default_start, alter_info, VERS_SYS_START_FLAG) || vers_create_sys_field(thd, default_end, alter_info, VERS_SYS_END_FLAG)) @@ -7375,7 +7375,7 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info, DBUG_ASSERT(end.str); as_row= start_end_t(start, end); - system_time= as_row; + period= as_row; if (alter_info->create_list.elements) { @@ -7461,7 +7461,7 @@ Vers_parse_info::fix_create_like(Alter_info &alter_info, HA_CREATE_INFO &create_ } as_row= start_end_t(f_start->field_name, f_end->field_name); - system_time= as_row; + period= as_row; create_info.options|= HA_VERSIONED_TABLE; return false; @@ -7486,14 +7486,14 @@ bool Vers_parse_info::check_conditions(const Lex_table_name &table_name, return true; } - if (!system_time.start || !system_time.end) + if (!period.start || !period.end) { my_error(ER_MISSING, MYF(0), table_name.str, "PERIOD FOR SYSTEM_TIME"); return true; } - if (!as_row.start.streq(system_time.start) || - !as_row.end.streq(system_time.end)) + if (!as_row.start.streq(period.start) || + !as_row.end.streq(period.end)) { my_error(ER_VERS_PERIOD_COLUMNS, MYF(0), as_row.start.str, as_row.end.str); return true; @@ -7583,3 +7583,98 @@ bool Vers_parse_info::check_sys_fields(const Lex_table_name &table_name, "ROW END" : found_flag ? "ROW START" : "ROW START/END"); return true; } + +static bool check_period_field(const Create_field* f, const char* name, + const char* period_name) +{ + bool res= false; + if (!f) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), name, period_name); + res= true; + } + else if (f->type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR) + { + my_error(ER_WRONG_FIELD_SPEC, MYF(0), name); + res= true; + } + else if (f->vcol_info || f->flags & VERS_SYSTEM_FIELD) + { + my_error(ER_PERIOD_FIELD_WRONG_ATTRIBUTES, MYF(0), + f->field_name.str, "GENERATED ALWAYS AS"); + } + + return res; +} + +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; + + if (!period_info.name) + return false; + + if (tmp_table()) + { + my_error(ER_PERIOD_TEMPORARY_NOT_ALLOWED, MYF(0)); + return true; + } + + Table_period_info::start_end_t &period= period_info.period; + const Create_field *row_start= NULL; + const Create_field *row_end= NULL; + List_iterator<Create_field> it(alter_info->create_list); + while (const Create_field *f= it++) + { + if (period.start.streq(f->field_name)) row_start= f; + else if (period.end.streq(f->field_name)) row_end= f; + + if (period_info.name.streq(f->field_name)) + { + my_error(ER_DUP_FIELDNAME, MYF(0), f->field_name.str); + return true; + } + } + + 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); + if (res) + return true; + + if (row_start->type_handler() != row_end->type_handler() + || row_start->length != row_end->length) + { + my_error(ER_PERIOD_TYPES_MISMATCH, MYF(0), period_info.name.str); + res= true; + } + + return res; +} + +bool +Table_scope_and_contents_source_st::fix_create_fields(THD *thd, + Alter_info *alter_info, + const TABLE_LIST &create_table, + bool create_select) +{ + if (vers_fix_system_fields(thd, alter_info, create_table, create_select)) + return true; + + if (!period_info.name) + return false; + + Table_period_info::start_end_t &period= period_info.period; + List_iterator<Create_field> it(alter_info->create_list); + while (Create_field *f= it++) + { + if (period.start.streq(f->field_name) || period.end.streq(f->field_name)) + { + f->period= &period_info; + f->flags|= NOT_NULL_FLAG; + } + } + return false; +} diff --git a/sql/handler.h b/sql/handler.h index 09c9c9a6849..2348575651a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1968,57 +1968,61 @@ enum vers_sys_type_t VERS_TRX_ID }; -extern const LEX_CSTRING null_clex_str; - -struct Vers_parse_info +struct Table_period_info { - Vers_parse_info() : - check_unit(VERS_UNDEFINED), - versioned_fields(false), - unversioned_fields(false) - {} + Table_period_info() {} + Table_period_info(const char *name_arg, size_t size) : + name(name_arg, size) {} - void init() // Deep initialization - { - system_time= start_end_t(null_clex_str, null_clex_str); - as_row= start_end_t(null_clex_str, null_clex_str); - check_unit= VERS_UNDEFINED; - versioned_fields= false; - unversioned_fields= false; - } + Lex_ident name; struct start_end_t { - start_end_t() - {} - start_end_t(LEX_CSTRING _start, LEX_CSTRING _end) : + start_end_t() {}; + start_end_t(const LEX_CSTRING& _start, const LEX_CSTRING& _end) : start(_start), end(_end) {} Lex_ident start; Lex_ident end; }; + start_end_t period; - start_end_t system_time; - start_end_t as_row; - vers_sys_type_t check_unit; + bool is_set() const + { + DBUG_ASSERT(bool(period.start) == bool(period.end)); + return period.start; + } - void set_system_time(Lex_ident start, Lex_ident end) + void set_period(const Lex_ident& start, const Lex_ident& end) { - system_time.start= start; - system_time.end= end; + period.start= start; + period.end= end; } +}; + +struct Vers_parse_info: public Table_period_info +{ + Vers_parse_info() : + Table_period_info(STRING_WITH_LEN("SYSTEM_TIME")), + check_unit(VERS_UNDEFINED), + versioned_fields(false), + unversioned_fields(false) + {} + + Table_period_info::start_end_t as_row; + vers_sys_type_t check_unit; protected: friend struct Table_scope_and_contents_source_st; void set_start(const LEX_CSTRING field_name) { as_row.start= field_name; - system_time.start= field_name; + period.start= field_name; } void set_end(const LEX_CSTRING field_name) { as_row.end= field_name; - system_time.end= field_name; + period.end= field_name; } bool is_start(const char *name) const; bool is_end(const char *name) const; @@ -2027,7 +2031,7 @@ protected: bool fix_implicit(THD *thd, Alter_info *alter_info); operator bool() const { - return as_row.start || as_row.end || system_time.start || system_time.end; + return as_row.start || as_row.end || period.start || period.end; } bool need_check(const Alter_info *alter_info) const; bool check_conditions(const Lex_table_name &table_name, @@ -2151,21 +2155,27 @@ struct Table_scope_and_contents_source_st: SQL_I_List<TABLE_LIST> merge_list; Vers_parse_info vers_info; + Table_period_info period_info; void init() { Table_scope_and_contents_source_pod_st::init(); merge_list.empty(); - vers_info.init(); + vers_info= {}; + period_info= {}; } - bool vers_fix_system_fields(THD *thd, Alter_info *alter_info, + bool fix_create_fields(THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table, bool create_select= false); + bool check_fields(THD *thd, Alter_info *alter_info, TABLE_LIST &create_table); + + bool vers_fix_system_fields(THD *thd, Alter_info *alter_info, + const TABLE_LIST &create_table, + bool create_select= false); bool vers_check_system_fields(THD *thd, Alter_info *alter_info, const TABLE_LIST &create_table); - }; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index f80ae99ac50..dcac7163ad6 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7936,3 +7936,11 @@ ER_USER_IS_BLOCKED ER_ACCOUNT_HAS_BEEN_LOCKED eng "Access denied, this account is locked" rum "Acces refuzat, acest cont este blocat" +ER_PERIOD_TEMPORARY_NOT_ALLOWED + eng "Application-time period table cannot be temporary" +ER_PERIOD_TYPES_MISMATCH + eng "Fields of PERIOD FOR %`s have different types" +ER_MORE_THAN_ONE_PERIOD + eng "Cannot specify more than one application-time period" +ER_PERIOD_FIELD_WRONG_ATTRIBUTES + eng "Period field %`s cannot be %s" diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4af0f919c91..43f20a4fa4c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -4189,7 +4189,7 @@ public: void add_key_to_list(LEX_CSTRING *field_name, enum Key::Keytype type, bool check_exists); // Add a constraint as a part of CREATE TABLE or ALTER TABLE - bool add_constraint(LEX_CSTRING *name, Virtual_column_info *constr, + bool add_constraint(const LEX_CSTRING *name, Virtual_column_info *constr, bool if_not_exists) { constr->name= *name; @@ -4271,6 +4271,25 @@ public: { return create_info.vers_info; } + + 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 (info.is_set()) + { + my_error(ER_MORE_THAN_ONE_PERIOD, MYF(0)); + return 1; + } + 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); + return 0; + } + sp_package *get_sp_package() const; /** diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 57cec6bacff..8880c5fe9a9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4311,8 +4311,8 @@ mysql_execute_command(THD *thd) } else { - if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table) || - create_info.vers_check_system_fields(thd, &alter_info, *create_table)) + if (create_info.fix_create_fields(thd, &alter_info, *create_table) || + create_info.check_fields(thd, &alter_info, *create_table)) goto end_with_restore_list; /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 80884d66590..291df4305cd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2047,6 +2047,22 @@ end_options: append_directory(thd, packet, "INDEX", create_info.index_file_name); } +static void append_period(THD *thd, String *packet, const LEX_CSTRING &start, + const LEX_CSTRING &end, const LEX_CSTRING &period, + bool ident) +{ + packet->append(STRING_WITH_LEN(",\n PERIOD FOR ")); + if (ident) + append_identifier(thd, packet, period.str, period.length); + else + packet->append(period); + packet->append(STRING_WITH_LEN(" (")); + append_identifier(thd, packet, start.str, start.length); + packet->append(STRING_WITH_LEN(", ")); + append_identifier(thd, packet, end.str, end.length); + packet->append(STRING_WITH_LEN(")")); +} + /* Build a CREATE TABLE statement for a table. @@ -2085,6 +2101,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, KEY *key_info; TABLE *table= table_list->table; TABLE_SHARE *share= table->s; + TABLE_SHARE::period_info_t &period= share->period; sql_mode_t sql_mode= thd->variables.sql_mode; bool explicit_fields= false; bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | @@ -2364,11 +2381,8 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, DBUG_ASSERT(!explicit_fields || fe->invisible < INVISIBLE_SYSTEM); if (explicit_fields) { - packet->append(STRING_WITH_LEN(",\n PERIOD FOR SYSTEM_TIME (")); - append_identifier(thd,packet,fs->field_name.str, fs->field_name.length); - packet->append(STRING_WITH_LEN(", ")); - append_identifier(thd,packet,fe->field_name.str, fe->field_name.length); - packet->append(STRING_WITH_LEN(")")); + append_period(thd, packet, fs->field_name, fe->field_name, + table->s->vers.name, false); } else { @@ -2377,6 +2391,15 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, } } + if (period.name) + { + append_period(thd, packet, + period.start_field(share)->field_name, + period.end_field(share)->field_name, + period.name, true); + } + + /* Get possible foreign key definitions stored in InnoDB and append them to the CREATE TABLE statement diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a3f1f616edd..13674392bb0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2998,7 +2998,8 @@ CHARSET_INFO* get_sql_field_charset(Column_definition *sql_field, by adding the features DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. If the first TIMESTAMP column appears to be nullable, or to have an - explicit default, or to be a virtual column, then no promition is done. + explicit default, or to be a virtual column, or to be part of table period, + then no promotion is done. @param column_definitions The list of column definitions, in the physical order in which they appear in the table. @@ -3019,6 +3020,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions) column_definition->default_value == NULL && // no constant default, column_definition->unireg_check == Field::NONE && // no function default column_definition->vcol_info == NULL && + column_definition->period == NULL && !(column_definition->flags & VERS_SYSTEM_FIELD)) // column isn't generated { DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to " diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bdc1893637d..1f0bf717ed4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6641,7 +6641,12 @@ period_for_system_time: PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' ident ',' ident ')' { Vers_parse_info &info= Lex->vers_get_info(); - info.set_system_time($4, $6); + info.set_period($4, $6); + } + | PERIOD_SYM FOR_SYM ident '(' ident ',' ident ')' + { + if (Lex->add_period($3, $5, $7)) + MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 6a6c901c197..46f4ee8f7a5 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -6579,7 +6579,12 @@ period_for_system_time: PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' ident ',' ident ')' { Vers_parse_info &info= Lex->vers_get_info(); - info.set_system_time($4, $6); + info.set_period($4, $6); + } + | PERIOD_SYM FOR_SYM ident '(' ident ',' ident ')' + { + if (Lex->add_period($3, $5, $7)) + MYSQL_YYABORT; } ; diff --git a/sql/table.cc b/sql/table.cc index 75f5a464186..c31b93d4d8e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -50,6 +50,17 @@ #define MYSQL57_GENERATED_FIELD 128 #define MYSQL57_GCOL_HEADER_SIZE 4 +struct extra2_fields +{ + LEX_CUSTRING version; + LEX_CUSTRING options; + Lex_ident engine; + LEX_CUSTRING gis; + LEX_CUSTRING field_flags; + const uchar *system_period; + LEX_CUSTRING application_period; +}; + static Virtual_column_info * unpack_vcol_info_from_frm(THD *, MEM_ROOT *, TABLE *, String *, Virtual_column_info **, bool *); static bool check_vcol_forward_refs(Field *, Virtual_column_info *, @@ -968,7 +979,7 @@ bool Column_definition_attributes::frm_unpack_charset(TABLE_SHARE *share, csname= tmp; } my_printf_error(ER_UNKNOWN_COLLATION, - "Unknown collation '%s' in table '%-.64s' definition", + "Unknown collation '%s' in table '%-.64s' definition", MYF(0), csname, share->table_name.str); return true; } @@ -1352,6 +1363,103 @@ void TABLE::find_constraint_correlated_indexes() } +bool TABLE_SHARE::init_period_from_extra2(period_info_t &period, + const uchar *data) +{ + period.start_fieldno= uint2korr(data); + period.end_fieldno= uint2korr(data + frm_fieldno_size); + return period.start_fieldno >= fields || period.end_fieldno >= fields; +} + + +static +bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields) +{ + const uchar *extra2= frm_image + 64; + + DBUG_ENTER("read_extra2"); + + memset(fields, 0, sizeof(extra2_fields)); + + if (*extra2 != '/') // old frm had '/' there + { + const uchar *e2end= extra2 + len; + while (extra2 + 3 <= e2end) + { + uchar type= *extra2++; + size_t length= *extra2++; + if (!length) + { + if (extra2 + 2 >= e2end) + DBUG_RETURN(true); + length= uint2korr(extra2); + extra2+= 2; + if (length < 256) + DBUG_RETURN(true); + } + if (extra2 + length > e2end) + DBUG_RETURN(true); + switch (type) { + case EXTRA2_TABLEDEF_VERSION: + if (fields->version.str) // see init_from_sql_statement_string() + { + if (length != fields->version.length) + DBUG_RETURN(true); + } + else + { + fields->version.str= extra2; + fields->version.length= length; + } + break; + case EXTRA2_ENGINE_TABLEOPTS: + if (fields->options.str) + DBUG_RETURN(true); + fields->options.str= extra2; + fields->options.length= length; + break; + case EXTRA2_DEFAULT_PART_ENGINE: + fields->engine.set((char*)extra2, length); + break; + case EXTRA2_GIS: +#ifdef HAVE_SPATIAL + if (fields->gis.str) + DBUG_RETURN(true); + fields->gis.str= extra2; + fields->gis.length= length; +#endif /*HAVE_SPATIAL*/ + break; + case EXTRA2_PERIOD_FOR_SYSTEM_TIME: + if (fields->system_period || length != 2 * sizeof(uint16)) + DBUG_RETURN(true); + fields->system_period = extra2; + break; + case EXTRA2_FIELD_FLAGS: + if (fields->field_flags.str) + DBUG_RETURN(true); + fields->field_flags.str= extra2; + fields->field_flags.length= length; + break; + case EXTRA2_APPLICATION_TIME_PERIOD: + if (fields->application_period.str) + DBUG_RETURN(true); + fields->application_period.str= extra2; + fields->application_period.length= length; + break; + default: + /* abort frm parsing if it's an unknown but important extra2 value */ + if (type >= EXTRA2_ENGINE_IMPORTANT) + DBUG_RETURN(true); + } + extra2+= length; + } + if (extra2 != e2end) + DBUG_RETURN(true); + } + DBUG_RETURN(false); +} + + /** Read data from a binary .frm file image into a TABLE_SHARE @@ -1380,7 +1488,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint i; bool use_hash, mysql57_null_bits= 0; char *keynames, *names, *comment_pos; - const uchar *forminfo, *extra2; + const uchar *forminfo; const uchar *frm_image_end = frm_image + frm_length; uchar *record, *null_flags, *null_pos, *UNINIT_VAR(mysql57_vcol_null_pos); const uchar *disk_buff, *strpos; @@ -1395,21 +1503,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, my_bitmap_map *bitmaps; bool null_bits_are_used; uint vcol_screen_length; - size_t UNINIT_VAR(options_len); uchar *vcol_screen_pos; - const uchar *options= 0; - LEX_CUSTRING gis_options= { NULL, 0}; + LEX_CUSTRING options; KEY first_keyinfo; uint len; uint ext_key_parts= 0; plugin_ref se_plugin= 0; - const uchar *system_period= 0; bool vers_can_native= false; - const uchar *extra2_field_flags= 0; - size_t extra2_field_flags_length= 0; MEM_ROOT *old_root= thd->mem_root; Virtual_column_info **table_check_constraints; + extra2_fields extra2; + DBUG_ENTER("TABLE_SHARE::init_from_binary_frm_image"); keyinfo= &first_keyinfo; @@ -1438,90 +1543,27 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, /* Length of the MariaDB extra2 segment in the form file. */ len = uint2korr(frm_image+4); - extra2= frm_image + 64; - if (*extra2 != '/') // old frm had '/' there - { - const uchar *e2end= extra2 + len; - while (extra2 + 3 <= e2end) - { - uchar type= *extra2++; - size_t length= *extra2++; - if (!length) - { - if (extra2 + 2 >= e2end) - goto err; - length= uint2korr(extra2); - extra2+= 2; - if (length < 256) - goto err; - } - if (extra2 + length > e2end) - goto err; - switch (type) { - case EXTRA2_TABLEDEF_VERSION: - if (tabledef_version.str) // see init_from_sql_statement_string() - { - if (length != tabledef_version.length || - memcmp(extra2, tabledef_version.str, length)) - goto err; - } - else - { - tabledef_version.length= length; - tabledef_version.str= (uchar*)memdup_root(&mem_root, extra2, length); - if (!tabledef_version.str) - goto err; - } - break; - case EXTRA2_ENGINE_TABLEOPTS: - if (options) - goto err; - /* remember but delay parsing until we have read fields and keys */ - options= extra2; - options_len= length; - break; - case EXTRA2_DEFAULT_PART_ENGINE: + if (read_extra2(frm_image, len, &extra2)) + goto err; + + tabledef_version.length= extra2.version.length; + tabledef_version.str= (uchar*)memdup_root(&mem_root, extra2.version.str, + extra2.version.length); + if (!tabledef_version.str) + goto err; + + /* remember but delay parsing until we have read fields and keys */ + options= extra2.options; + #ifdef WITH_PARTITION_STORAGE_ENGINE - { - LEX_CSTRING name= { (char*)extra2, length }; - share->default_part_plugin= ha_resolve_by_name(NULL, &name, false); - if (!share->default_part_plugin) - goto err; - } -#endif - break; - case EXTRA2_GIS: -#ifdef HAVE_SPATIAL - { - if (gis_options.str) - goto err; - gis_options.str= extra2; - gis_options.length= length; - } -#endif /*HAVE_SPATIAL*/ - break; - case EXTRA2_PERIOD_FOR_SYSTEM_TIME: - if (system_period || length != 2 * sizeof(uint16)) - goto err; - system_period = extra2; - break; - case EXTRA2_FIELD_FLAGS: - if (extra2_field_flags) - goto err; - extra2_field_flags= extra2; - extra2_field_flags_length= length; - break; - default: - /* abort frm parsing if it's an unknown but important extra2 value */ - if (type >= EXTRA2_ENGINE_IMPORTANT) - goto err; - } - extra2+= length; - } - if (extra2 != e2end) + if (extra2.engine) + { + share->default_part_plugin= ha_resolve_by_name(NULL, &extra2.engine, false); + if (!share->default_part_plugin) goto err; } +#endif if (frm_length < FRM_HEADER_SIZE + len || !(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len))) @@ -1798,11 +1840,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS_legacy) { - if (options) + if (options.str) goto err; - options_len= uint4korr(next_chunk); - options= next_chunk + 4; - next_chunk+= options_len + 4; + options.length= uint4korr(next_chunk); + options.str= next_chunk + 4; + next_chunk+= options.length + 4; } DBUG_ASSERT(next_chunk <= buff_end); } @@ -1830,7 +1872,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, disk_buff= frm_image + pos + FRM_FORMINFO_SIZE; share->fields= uint2korr(forminfo+258); - if (extra2_field_flags && extra2_field_flags_length != share->fields) + if (extra2.field_flags.str && extra2.field_flags.length != share->fields) goto err; pos= uint2korr(forminfo+260); /* Length of all screens */ n_length= uint2korr(forminfo+268); @@ -1965,27 +2007,36 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } /* Set system versioning information. */ - if (system_period == NULL) + vers.name= Lex_ident(STRING_WITH_LEN("SYSTEM_TIME")); + if (extra2.system_period == NULL) { versioned= VERS_UNDEFINED; - row_start_field= 0; - row_end_field= 0; + vers.start_fieldno= 0; + vers.end_fieldno= 0; } else { DBUG_PRINT("info", ("Setting system versioning informations")); - uint16 row_start= uint2korr(system_period); - uint16 row_end= uint2korr(system_period + sizeof(uint16)); - if (row_start >= share->fields || row_end >= share->fields) + if (init_period_from_extra2(vers, extra2.system_period)) goto err; - DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", row_start, row_end)); + DBUG_PRINT("info", ("Columns with system versioning: [%d, %d]", + vers.start_fieldno, vers.end_fieldno)); versioned= VERS_TIMESTAMP; vers_can_native= plugin_hton(se_plugin)->flags & HTON_NATIVE_SYS_VERSIONING; - row_start_field= row_start; - row_end_field= row_end; status_var_increment(thd->status_var.feature_system_versioning); } // if (system_period == NULL) + if (extra2.application_period.str) + { + period.name.length= extra2.application_period.length - 2 * frm_fieldno_size; + period.name.str= strmake_root(&mem_root, + (char*)extra2.application_period.str, + period.name.length); + const uchar *field_pos= extra2.application_period.str + period.name.length; + if (init_period_from_extra2(period, field_pos)) + goto err; + } + for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) { uint interval_nr= 0, recpos; @@ -2067,7 +2118,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, goto err; // Not supported field type if (handler->Column_definition_attributes_frm_unpack(&attr, share, strpos, - &gis_options)) + &extra2.gis)) goto err; } @@ -2178,9 +2229,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (versioned) { - if (i == row_start_field) + if (i == vers.start_fieldno) flags|= VERS_SYS_START_FLAG; - else if (i == row_end_field) + else if (i == vers.end_fieldno) flags|= VERS_SYS_END_FLAG; if (flags & VERS_SYSTEM_FIELD) @@ -2229,9 +2280,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, reg_field->comment=comment; reg_field->vcol_info= vcol_info; reg_field->flags|= flags; - if (extra2_field_flags) + if (extra2.field_flags.str) { - uchar flags= *extra2_field_flags++; + uchar flags= *extra2.field_flags.str++; if (flags & VERS_OPTIMIZED_UPDATE) reg_field->flags|= VERS_UPDATE_UNVERSIONED_FLAG; @@ -2740,10 +2791,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, (uint) (share->table_check_constraints - share->field_check_constraints)); - if (options) + if (options.str) { - DBUG_ASSERT(options_len); - if (engine_table_options_frm_read(options, options_len, share)) + DBUG_ASSERT(options.length); + if (engine_table_options_frm_read(options.str, options.length, share)) goto err; } if (parse_engine_table_options(thd, handler_file->partition_ht(), share)) @@ -6631,9 +6682,9 @@ void TABLE::mark_columns_needed_for_delete() if (s->versioned) { - bitmap_set_bit(read_set, s->vers_start_field()->field_index); - bitmap_set_bit(read_set, s->vers_end_field()->field_index); - bitmap_set_bit(write_set, s->vers_end_field()->field_index); + bitmap_set_bit(read_set, s->vers.start_field(s)->field_index); + bitmap_set_bit(read_set, s->vers.end_field(s)->field_index); + bitmap_set_bit(write_set, s->vers.end_field(s)->field_index); } } diff --git a/sql/table.h b/sql/table.h index 82fefe60e0b..0dc4728d0ce 100644 --- a/sql/table.h +++ b/sql/table.h @@ -768,20 +768,36 @@ struct TABLE_SHARE /** System versioning support. - */ + */ + struct period_info_t + { + uint16 start_fieldno; + uint16 end_fieldno; + Lex_ident name; + Field *start_field(TABLE_SHARE *s) const + { + return s->field[start_fieldno]; + } + Field *end_field(TABLE_SHARE *s) const + { + return s->field[end_fieldno]; + } + }; vers_sys_type_t versioned; - uint16 row_start_field; - uint16 row_end_field; + period_info_t vers; + period_info_t period; + + bool init_period_from_extra2(period_info_t &period, const uchar *data); Field *vers_start_field() { - return field[row_start_field]; + return field[vers.start_fieldno]; } Field *vers_end_field() { - return field[row_end_field]; + return field[vers.end_fieldno]; } /** @@ -1546,13 +1562,13 @@ public: Field *vers_start_field() const { DBUG_ASSERT(s && s->versioned); - return field[s->row_start_field]; + return field[s->vers.start_fieldno]; } Field *vers_end_field() const { DBUG_ASSERT(s && s->versioned); - return field[s->row_end_field]; + return field[s->vers.end_fieldno]; } ulonglong vers_start_id() const; @@ -1758,6 +1774,9 @@ class IS_table_read_plan; /** The threshold size a blob field buffer before it is freed */ #define MAX_TDC_BLOB_SIZE 65536 +/** number of bytes used by field positional indexes in frm */ +constexpr uint frm_fieldno_size= 2; + class select_unit; class TMP_TABLE_PARAM; @@ -1868,6 +1887,8 @@ struct vers_select_conds_t Vers_history_point start; Vers_history_point end; + const TABLE_SHARE::period_info_t *period; + void empty() { type= SYSTEM_TIME_UNSPECIFIED; diff --git a/sql/unireg.cc b/sql/unireg.cc index 4692b2d74d1..9d4b7b93f0a 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -106,25 +106,19 @@ static uchar *extra2_write_field_properties(uchar *pos, return pos; } -static const bool ROW_START = true; -static const bool ROW_END = false; - -static inline +static uint16 -vers_get_field(HA_CREATE_INFO *create_info, List<Create_field> &create_fields, bool row_start) +get_fieldno_by_name(HA_CREATE_INFO *create_info, List<Create_field> &create_fields, + const Lex_ident field_name) { - DBUG_ASSERT(create_info->versioned()); - List_iterator<Create_field> it(create_fields); Create_field *sql_field = NULL; - const Lex_ident row_field= row_start ? create_info->vers_info.as_row.start - : create_info->vers_info.as_row.end; - DBUG_ASSERT(row_field); + DBUG_ASSERT(field_name); for (unsigned field_no = 0; (sql_field = it++); ++field_no) { - if (row_field.streq(sql_field->field_name)) + if (field_name.streq(sql_field->field_name)) { DBUG_ASSERT(field_no <= uint16(~0U)); return uint16(field_no); @@ -176,6 +170,8 @@ 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; uchar fileinfo[FRM_HEADER_SIZE],forminfo[FRM_FORMINFO_SIZE]; const partition_info *part_info= IF_PARTITIONING(thd->work_part_info, 0); bool error; @@ -287,6 +283,11 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING *table, extra2_size+= 1 + 1 + 2 * sizeof(uint16); } + if (create_info->period_info.name) + { + extra2_size+= 1 + (period_info_len > 255 ? 3 : 1) + period_info_len; + } + bool has_extra2_field_flags_= has_extra2_field_flags(create_fields); if (has_extra2_field_flags_) { @@ -349,13 +350,33 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING *table, } #endif /*HAVE_SPATIAL*/ + // PERIOD + if (create_info->period_info.name) + { + *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; + + int2store(pos, get_fieldno_by_name(create_info, create_fields, + create_info->period_info.period.start)); + pos+= frm_fieldno_size; + int2store(pos, get_fieldno_by_name(create_info, create_fields, + create_info->period_info.period.end)); + pos+= frm_fieldno_size; + } + if (create_info->versioned()) { *pos++= EXTRA2_PERIOD_FOR_SYSTEM_TIME; *pos++= 2 * sizeof(uint16); - int2store(pos, vers_get_field(create_info, create_fields, ROW_START)); + int2store(pos, get_fieldno_by_name(create_info, create_fields, + create_info->vers_info.as_row.start)); pos+= sizeof(uint16); - int2store(pos, vers_get_field(create_info, create_fields, ROW_END)); + int2store(pos, get_fieldno_by_name(create_info, create_fields, + create_info->vers_info.as_row.end)); pos+= sizeof(uint16); } diff --git a/sql/unireg.h b/sql/unireg.h index a24c1b516c5..dacf24ad7aa 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -171,6 +171,7 @@ enum extra2_frm_value_type { EXTRA2_DEFAULT_PART_ENGINE=1, EXTRA2_GIS=2, EXTRA2_PERIOD_FOR_SYSTEM_TIME=4, + EXTRA2_APPLICATION_TIME_PERIOD=8, #define EXTRA2_ENGINE_IMPORTANT 128 |