summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h4
-rw-r--r--sql/handler.cc109
-rw-r--r--sql/handler.h72
-rw-r--r--sql/share/errmsg-utf8.txt8
-rw-r--r--sql/sql_lex.h21
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_show.cc33
-rw-r--r--sql/sql_table.cc4
-rw-r--r--sql/sql_yacc.yy7
-rw-r--r--sql/sql_yacc_ora.yy7
-rw-r--r--sql/table.cc277
-rw-r--r--sql/table.h35
-rw-r--r--sql/unireg.cc47
-rw-r--r--sql/unireg.h1
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