Commit 02c712aa authored by Sergei Golubchik's avatar Sergei Golubchik

* frm extra2 segment.

* persistent table versions in the extra2
* ha_archive::frm_compare using TABLE_SHARE::tabledef_version
* distinguish between "important" and "optional" extra2 frm values
* write engine-defined attributes (aka "table options") to extra2, not to extra,
  but still read from the old location, if they're found there.
parent f6168bb6
...@@ -318,7 +318,7 @@ enum ha_base_keytype { ...@@ -318,7 +318,7 @@ enum ha_base_keytype {
#define HA_OPTION_NULL_FIELDS 1024 #define HA_OPTION_NULL_FIELDS 1024
#define HA_OPTION_PAGE_CHECKSUM 2048 #define HA_OPTION_PAGE_CHECKSUM 2048
/* .frm has extra create options in linked-list format */ /* .frm has extra create options in linked-list format */
#define HA_OPTION_TEXT_CREATE_OPTIONS (1L << 14) #define HA_OPTION_TEXT_CREATE_OPTIONS_legacy (1L << 14) /* 5.2 to 5.5, unused since 10.0 */
#define HA_OPTION_TEMP_COMPRESS_RECORD (1L << 15) /* set by isamchk */ #define HA_OPTION_TEMP_COMPRESS_RECORD (1L << 15) /* set by isamchk */
#define HA_OPTION_READ_ONLY_DATA (1L << 16) /* Set by isamchk */ #define HA_OPTION_READ_ONLY_DATA (1L << 16) /* Set by isamchk */
#define HA_OPTION_NO_CHECKSUM (1L << 17) #define HA_OPTION_NO_CHECKSUM (1L << 17)
......
...@@ -12701,12 +12701,12 @@ CREATE TABLE t1(a INT, b BLOB) ENGINE=archive; ...@@ -12701,12 +12701,12 @@ CREATE TABLE t1(a INT, b BLOB) ENGINE=archive;
SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DATA_LENGTH AVG_ROW_LENGTH DATA_LENGTH AVG_ROW_LENGTH
535 15 550 15
INSERT INTO t1 VALUES(1, 'sampleblob1'),(2, 'sampleblob2'); INSERT INTO t1 VALUES(1, 'sampleblob1'),(2, 'sampleblob2');
SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DATA_LENGTH AVG_ROW_LENGTH DATA_LENGTH AVG_ROW_LENGTH
569 284 584 292
DROP TABLE t1; DROP TABLE t1;
SET @save_join_buffer_size= @@join_buffer_size; SET @save_join_buffer_size= @@join_buffer_size;
SET @@join_buffer_size= 8192; SET @@join_buffer_size= 8192;
...@@ -12818,10 +12818,11 @@ select * from t1; ...@@ -12818,10 +12818,11 @@ select * from t1;
a b a b
flush tables; flush tables;
select * from t1; select * from t1;
a b ERROR HY000: Table 't1' is marked as crashed and should be repaired
1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
show warnings; show warnings;
Level Code Message Level Code Message
Warning 127 Got error 127 when reading table `test`.`t1`
Error 1194 Table 't1' is marked as crashed and should be repaired
drop table t1; drop table t1;
create temporary table t1 (a int) engine=archive; create temporary table t1 (a int) engine=archive;
insert t1 values (1),(2),(3); insert t1 values (1),(2),(3);
......
...@@ -1738,7 +1738,7 @@ select * from t1; # open the table to create the frm ...@@ -1738,7 +1738,7 @@ select * from t1; # open the table to create the frm
flush tables; # and close the table again flush tables; # and close the table again
--remove_file $MYSQLD_DATADIR/test/t1.ARZ --remove_file $MYSQLD_DATADIR/test/t1.ARZ
copy_file std_data/t917689.ARZ $MYSQLD_DATADIR/test/t1.ARZ; copy_file std_data/t917689.ARZ $MYSQLD_DATADIR/test/t1.ARZ;
#--error ER_CRASHED_ON_USAGE --error ER_CRASHED_ON_USAGE
select * from t1; select * from t1;
show warnings; show warnings;
drop table t1; drop table t1;
......
...@@ -17,6 +17,8 @@ select * from t1; ...@@ -17,6 +17,8 @@ select * from t1;
a a
1 1
2 2
t1.ARZ
t1.frm
# #
# show tables # show tables
# #
...@@ -28,10 +30,9 @@ show tables; ...@@ -28,10 +30,9 @@ show tables;
Tables_in_test Tables_in_test
t1 t1
t2 t2
select * from t1; t1.ARZ
a t2.ARZ
1 t2.frm
2
# #
# show full tables # show full tables
# #
...@@ -40,29 +41,27 @@ show full tables; ...@@ -40,29 +41,27 @@ show full tables;
Tables_in_test Table_type Tables_in_test Table_type
t1 BASE TABLE t1 BASE TABLE
t2 BASE TABLE t2 BASE TABLE
select * from t1; t1.ARZ
a t2.ARZ
1 t2.frm
2
# #
# discover on truncate # discover on truncate
# #
flush tables; flush tables;
truncate table t1; truncate table t1;
ERROR HY000: Table storage engine for 't1' doesn't have this option ERROR HY000: Table storage engine for 't1' doesn't have this option
show tables; t1.ARZ
Tables_in_test t1.frm
t1 t2.ARZ
t2 t2.frm
# #
# discover on rename # discover on rename
# #
flush tables; flush tables;
rename table t2 to t0; rename table t2 to t0;
show tables; t0.ARZ
Tables_in_test t1.ARZ
t0 t1.frm
t1
# #
# discover on HA_ERR_TABLE_DEF_CHANGED # discover on HA_ERR_TABLE_DEF_CHANGED
# #
...@@ -77,9 +76,7 @@ t1 CREATE TABLE `t1` ( ...@@ -77,9 +76,7 @@ t1 CREATE TABLE `t1` (
# #
flush tables; flush tables;
drop table t1; drop table t1;
show tables; t0.ARZ
Tables_in_test
t0
# #
# discover of table non-existance on drop # discover of table non-existance on drop
# #
...@@ -89,6 +86,9 @@ flush tables; ...@@ -89,6 +86,9 @@ flush tables;
select * from t1; select * from t1;
ERROR 42S02: Table 'test.t1' doesn't exist ERROR 42S02: Table 'test.t1' doesn't exist
drop table t0; drop table t0;
show status like 'Handler_discover';
Variable_name Value
Handler_discover 7
# #
# Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE # Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE
# #
......
...@@ -13,6 +13,7 @@ remove_file $mysqld_datadir/test/t1.frm; ...@@ -13,6 +13,7 @@ remove_file $mysqld_datadir/test/t1.frm;
flush tables; flush tables;
insert t1 values (2); insert t1 values (2);
select * from t1; select * from t1;
--list_files $mysqld_datadir/test
--echo # --echo #
--echo # show tables --echo # show tables
...@@ -22,24 +23,22 @@ select * from t2; ...@@ -22,24 +23,22 @@ select * from t2;
remove_file $mysqld_datadir/test/t1.frm; remove_file $mysqld_datadir/test/t1.frm;
flush tables; flush tables;
show tables; show tables;
select * from t1; --list_files $mysqld_datadir/test
--echo # --echo #
--echo # show full tables --echo # show full tables
--echo # --echo #
remove_file $mysqld_datadir/test/t1.frm;
flush tables; flush tables;
show full tables; show full tables;
select * from t1; --list_files $mysqld_datadir/test
--echo # --echo #
--echo # discover on truncate --echo # discover on truncate
--echo # --echo #
remove_file $mysqld_datadir/test/t1.frm;
flush tables; flush tables;
--error ER_ILLEGAL_HA --error ER_ILLEGAL_HA
truncate table t1; truncate table t1;
show tables; --list_files $mysqld_datadir/test
--echo # --echo #
--echo # discover on rename --echo # discover on rename
...@@ -47,7 +46,7 @@ show tables; ...@@ -47,7 +46,7 @@ show tables;
remove_file $mysqld_datadir/test/t2.frm; remove_file $mysqld_datadir/test/t2.frm;
flush tables; flush tables;
rename table t2 to t0; rename table t2 to t0;
show tables; --list_files $mysqld_datadir/test
--echo # --echo #
--echo # discover on HA_ERR_TABLE_DEF_CHANGED --echo # discover on HA_ERR_TABLE_DEF_CHANGED
...@@ -63,7 +62,7 @@ show create table t1; ...@@ -63,7 +62,7 @@ show create table t1;
remove_file $mysqld_datadir/test/t1.frm; remove_file $mysqld_datadir/test/t1.frm;
flush tables; flush tables;
drop table t1; drop table t1;
show tables; --list_files $mysqld_datadir/test
--echo # --echo #
--echo # discover of table non-existance on drop --echo # discover of table non-existance on drop
...@@ -74,6 +73,8 @@ flush tables; ...@@ -74,6 +73,8 @@ flush tables;
--error ER_NO_SUCH_TABLE --error ER_NO_SUCH_TABLE
select * from t1; select * from t1;
drop table t0; drop table t0;
--list_files $mysqld_datadir/test
show status like 'Handler_discover';
--echo # --echo #
--echo # Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE --echo # Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE
......
...@@ -15,10 +15,10 @@ ENGINE = ARCHIVE; ...@@ -15,10 +15,10 @@ ENGINE = ARCHIVE;
INSERT INTO t1 VALUES(CURRENT_DATE); INSERT INTO t1 VALUES(CURRENT_DATE);
SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
DATA_LENGTH INDEX_LENGTH DATA_LENGTH INDEX_LENGTH
520 0 535 0
SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'; SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
DATA_LENGTH INDEX_LENGTH DATA_LENGTH INDEX_LENGTH
520 0 535 0
DROP TABLE t1; DROP TABLE t1;
drop database if exists db99; drop database if exists db99;
drop table if exists t1; drop table if exists t1;
......
...@@ -123,7 +123,7 @@ void my_uuid_init(ulong seed1, ulong seed2) ...@@ -123,7 +123,7 @@ void my_uuid_init(ulong seed1, ulong seed2)
Create a global unique identifier (uuid) Create a global unique identifier (uuid)
@func my_uuid() @func my_uuid()
@param to Store uuid here. Must be of size MY_uuid_SIZE (16) @param to Store uuid here. Must be of size MY_UUID_SIZE (16)
*/ */
void my_uuid(uchar *to) void my_uuid(uchar *to)
......
...@@ -1360,6 +1360,7 @@ enum ha_choice { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES }; ...@@ -1360,6 +1360,7 @@ enum ha_choice { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES };
struct HA_CREATE_INFO struct HA_CREATE_INFO
{ {
CHARSET_INFO *table_charset, *default_table_charset; CHARSET_INFO *table_charset, *default_table_charset;
LEX_CUSTRING tabledef_version;
LEX_STRING connect_string; LEX_STRING connect_string;
const char *password, *tablespace; const char *password, *tablespace;
LEX_STRING comment; LEX_STRING comment;
...@@ -1393,6 +1394,7 @@ struct HA_CREATE_INFO ...@@ -1393,6 +1394,7 @@ struct HA_CREATE_INFO
enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY
enum ha_choice page_checksum; ///< If we have page_checksums enum ha_choice page_checksum; ///< If we have page_checksums
engine_option_value *option_list; ///< list of table create options engine_option_value *option_list; ///< list of table create options
/* the following three are only for ALTER TABLE, check_if_incompatible_data() */ /* the following three are only for ALTER TABLE, check_if_incompatible_data() */
ha_table_option_struct *option_struct; ///< structure with parsed table options ha_table_option_struct *option_struct; ///< structure with parsed table options
ha_field_option_struct **fields_option_struct; ///< array of field option structures ha_field_option_struct **fields_option_struct; ///< array of field option structures
......
/* /*
Copyright (c) 2000, 2011, Oracle and/or its affiliates. Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2008-2011 Monty Program Ab Copyright (c) 2008, 2013, Monty Program Ab
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -706,7 +706,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, ...@@ -706,7 +706,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint i,j; uint i,j;
bool use_hash; bool use_hash;
char *keynames, *names, *comment_pos; char *keynames, *names, *comment_pos;
const uchar *forminfo; const uchar *forminfo, *extra2;
const uchar *frm_image_end = frm_image + frm_length; const uchar *frm_image_end = frm_image + frm_length;
uchar *record, *null_flags, *null_pos; uchar *record, *null_flags, *null_pos;
const uchar *disk_buff, *strpos; const uchar *disk_buff, *strpos;
...@@ -723,7 +723,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, ...@@ -723,7 +723,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
bool null_bits_are_used; bool null_bits_are_used;
uint vcol_screen_length, UNINIT_VAR(options_len); uint vcol_screen_length, UNINIT_VAR(options_len);
char *vcol_screen_pos; char *vcol_screen_pos;
const uchar *UNINIT_VAR(options); const uchar *options= 0;
KEY first_keyinfo; KEY first_keyinfo;
uint len; uint len;
KEY_PART_INFO *first_key_part= NULL; KEY_PART_INFO *first_key_part= NULL;
...@@ -749,8 +749,60 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, ...@@ -749,8 +749,60 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
new_frm_ver= (frm_image[2] - FRM_VER); new_frm_ver= (frm_image[2] - FRM_VER);
field_pack_length= new_frm_ver < 2 ? 11 : 17; field_pack_length= new_frm_ver < 2 ? 11 : 17;
/* Position of the form in the form file. */ /* Length of the MariaDB extra2 segment in the form file. */
len = uint2korr(frm_image+4); len = uint2korr(frm_image+4);
extra2= frm_image + 64;
if (*extra2 != '/') // old frm had '/' there
{
const uchar *e2end= extra2 + len;
while (extra2 < e2end)
{
uchar type= *extra2++;
size_t length= *extra2++;
if (!length)
{
length= uint2korr(extra2);
extra2+=2;
if (length < 256)
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
{
uchar *buf= (uchar*) alloc_root(&mem_root, length);
if (!buf)
goto err;
memcpy(buf, extra2, length);
tabledef_version.str= buf;
tabledef_version.length= length;
}
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;
default:
/* abort frm parsing if it's an unknown but important extra2 value */
if (type >= 128)
goto err;
}
extra2+= length;
}
if (extra2 > e2end)
goto err;
}
if (frm_length < FRM_HEADER_SIZE + len || if (frm_length < FRM_HEADER_SIZE + len ||
!(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len))) !(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len)))
goto err; goto err;
...@@ -1169,12 +1221,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, ...@@ -1169,12 +1221,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
DBUG_ASSERT(next_chunk <= buff_end); DBUG_ASSERT(next_chunk <= buff_end);
if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS) if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS_legacy)
{ {
/* if (options)
store options position, but skip till the time we will goto err;
know number of fields
*/
options_len= uint4korr(next_chunk); options_len= uint4korr(next_chunk);
options= next_chunk + 4; options= next_chunk + 4;
next_chunk+= options_len + 4; next_chunk+= options_len + 4;
...@@ -1839,7 +1889,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, ...@@ -1839,7 +1889,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
null_length, 255); null_length, 255);
} }
if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS) if (options)
{ {
DBUG_ASSERT(options_len); DBUG_ASSERT(options_len);
if (engine_table_options_frm_read(options, options_len, share)) if (engine_table_options_frm_read(options, options_len, share))
...@@ -2028,6 +2078,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, ...@@ -2028,6 +2078,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
thd->lex->create_info.db_type= plugin_data(db_plugin, handlerton *); thd->lex->create_info.db_type= plugin_data(db_plugin, handlerton *);
if (tabledef_version.str)
thd->lex->create_info.tabledef_version= tabledef_version;
file= mysql_create_frm_image(thd, db.str, table_name.str, file= mysql_create_frm_image(thd, db.str, table_name.str,
&thd->lex->create_info, &thd->lex->alter_info, &thd->lex->create_info, &thd->lex->alter_info,
0, 0, &frm); 0, 0, &frm);
...@@ -3086,7 +3139,7 @@ void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo, ...@@ -3086,7 +3139,7 @@ void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo,
fileinfo[3]= (uchar) ha_legacy_type( fileinfo[3]= (uchar) ha_legacy_type(
ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0)); ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0));
int2store(fileinfo+4,3);
/* /*
Keep in sync with pack_keys() in unireg.cc Keep in sync with pack_keys() in unireg.cc
For each key: For each key:
......
...@@ -616,6 +616,8 @@ struct TABLE_SHARE ...@@ -616,6 +616,8 @@ struct TABLE_SHARE
I_P_List <TABLE, TABLE_share> used_tables; I_P_List <TABLE, TABLE_share> used_tables;
I_P_List <TABLE, TABLE_share> free_tables; I_P_List <TABLE, TABLE_share> free_tables;
LEX_CUSTRING tabledef_version;
engine_option_value *option_list; /* text options for table */ engine_option_value *option_list; /* text options for table */
ha_table_option_struct *option_struct; /* structure with parsed options */ ha_table_option_struct *option_struct; /* structure with parsed options */
......
/* /*
Copyright (c) 2000, 2011, Oracle and/or its affiliates. Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2009, 2013, Monty Program Ab.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -122,13 +123,6 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, ...@@ -122,13 +123,6 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
create_fields, create_fields,
keys, key_info); keys, key_info);
DBUG_PRINT("info", ("Options length: %u", options_len)); DBUG_PRINT("info", ("Options length: %u", options_len));
if (options_len)
{
create_info->table_options|= HA_OPTION_TEXT_CREATE_OPTIONS;
create_info->extra_size+= (options_len + 4);
}
else
create_info->table_options&= ~HA_OPTION_TEXT_CREATE_OPTIONS;
/* /*
This gives us the byte-position of the character at This gives us the byte-position of the character at
...@@ -193,13 +187,31 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, ...@@ -193,13 +187,31 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
forminfo[46]=(uchar) create_info->comment.length; forminfo[46]=(uchar) create_info->comment.length;
} }
if (!create_info->tabledef_version.str)
{
uchar *to= (uchar*) thd->alloc(MY_UUID_SIZE);
if (unlikely(!to))
DBUG_RETURN(frm);
my_uuid(to);
create_info->tabledef_version.str= to;
create_info->tabledef_version.length= MY_UUID_SIZE;
}
DBUG_ASSERT(create_info->tabledef_version.length > 0);
DBUG_ASSERT(create_info->tabledef_version.length <= 255);
prepare_frm_header(thd, reclength, fileinfo, create_info, keys, key_info); prepare_frm_header(thd, reclength, fileinfo, create_info, keys, key_info);
/* one byte for a type, one or three for a length */
uint extra2_size= 1 + 1 + create_info->tabledef_version.length;
if (options_len)
extra2_size+= 1 + (options_len > 255 ? 3 : 1) + options_len;
key_buff_length= uint4korr(fileinfo+47); key_buff_length= uint4korr(fileinfo+47);
frm.length= FRM_HEADER_SIZE; // fileinfo; frm.length= FRM_HEADER_SIZE; // fileinfo;
frm.length+= uint2korr(fileinfo+4) + 4; // "form entry" frm.length+= extra2_size + 4; // mariadb extra2 frm segment
int2store(fileinfo+4, extra2_size);
int2store(fileinfo+6, frm.length); int2store(fileinfo+6, frm.length);
frm.length+= key_buff_length; frm.length+= key_buff_length;
frm.length+= reclength; // row with default values frm.length+= reclength; // row with default values
...@@ -214,11 +226,34 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, ...@@ -214,11 +226,34 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
if (!frm_ptr) if (!frm_ptr)
DBUG_RETURN(frm); DBUG_RETURN(frm);
pos = frm_ptr + uint2korr(fileinfo+6); /* write the extra2 segment */
key_info_length= pack_keys(pos, keys, key_info, data_offset); pos = frm_ptr + 64;
*pos++ = EXTRA2_TABLEDEF_VERSION;
*pos++ = create_info->tabledef_version.length;
memcpy(pos, create_info->tabledef_version.str,
create_info->tabledef_version.length);
pos+= create_info->tabledef_version.length;
if (options_len)
{
*pos++= EXTRA2_ENGINE_TABLEOPTS;
if (options_len < 255)
*pos++= options_len;
else
{
DBUG_ASSERT(options_len <= 65535); // FIXME if necessary
int2store(pos + 1, options_len);
pos+= 3;
}
pos= engine_table_options_frm_image(pos, create_info->option_list,
create_fields, keys, key_info);
}
memcpy(frm_ptr + FRM_HEADER_SIZE, "//", 3); int4store(pos, filepos); // end of the extra2 segment
int4store(frm_ptr + 67, filepos); pos+= 4;
DBUG_ASSERT(pos == frm_ptr + uint2korr(fileinfo+6));
key_info_length= pack_keys(pos, keys, key_info, data_offset);
maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000)); maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
int2store(forminfo+2,maxlength); int2store(forminfo+2,maxlength);
...@@ -285,19 +320,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, ...@@ -285,19 +320,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
pos+= create_info->comment.length; pos+= create_info->comment.length;
} }
if (options_len) memcpy(frm_ptr + filepos, forminfo, 288);
{ if (pack_fields(frm_ptr + filepos + 288, create_fields, data_offset))
int4store(pos, options_len);
pos+= 4;
engine_table_options_frm_image(pos,
create_info->option_list,
create_fields,
keys, key_info);
pos+= options_len;
}
memcpy(frm_ptr + filepos, forminfo, FRM_FORMINFO_SIZE);
if (pack_fields(frm_ptr + filepos + FRM_FORMINFO_SIZE, create_fields, data_offset))
goto err; goto err;
{ {
...@@ -332,14 +356,12 @@ err: ...@@ -332,14 +356,12 @@ err:
SYNOPSIS SYNOPSIS
rea_create_table() rea_create_table()
thd Thread handler thd Thread handler
frm binary frm image of the table to create
path Name of file (including database, without .frm) path Name of file (including database, without .frm)
db Data base name db Data base name
table_name Table name table_name Table name
create_info create info parameters create_info create info parameters
create_fields Fields to create file Handler to use or NULL if only frm needs to be created
keys number of keys to create
key_info Keys to create
file Handler to use
RETURN RETURN
0 ok 0 ok
......
...@@ -167,6 +167,22 @@ ...@@ -167,6 +167,22 @@
#include "sql_list.h" /* List<> */ #include "sql_list.h" /* List<> */
#include "field.h" /* Create_field */ #include "field.h" /* Create_field */
/*
Types of values in the MariaDB extra2 frm segment.
Each value is written as
type: 1 byte
length: 1 byte (1..255) or \0 and 2 bytes.
binary value of the 'length' bytes.
Older MariaDB servers can ignore values of unknown types if
the type code is less than 128. Otherwise older servers are required
to report an error.
*/
enum extra2_frm_value_type {
EXTRA2_TABLEDEF_VERSION=0,
EXTRA2_ENGINE_TABLEOPTS=128,
};
int rea_create_table(THD *thd, LEX_CUSTRING *frm, int rea_create_table(THD *thd, LEX_CUSTRING *frm,
const char *path, const char *db, const char *table_name, const char *path, const char *db, const char *table_name,
HA_CREATE_INFO *create_info, handler *file); HA_CREATE_INFO *create_info, handler *file);
......
...@@ -364,6 +364,8 @@ void read_header(azio_stream *s, unsigned char *buffer) ...@@ -364,6 +364,8 @@ void read_header(azio_stream *s, unsigned char *buffer)
{ {
if (buffer[0] == az_magic[0] && buffer[1] == az_magic[1]) if (buffer[0] == az_magic[0] && buffer[1] == az_magic[1])
{ {
uchar tmp[AZ_FRMVER_LEN + 2];
s->version= (unsigned int)buffer[AZ_VERSION_POS]; s->version= (unsigned int)buffer[AZ_VERSION_POS];
s->minor_version= (unsigned int)buffer[AZ_MINOR_VERSION_POS]; s->minor_version= (unsigned int)buffer[AZ_MINOR_VERSION_POS];
s->block_size= 1024 * buffer[AZ_BLOCK_POS]; s->block_size= 1024 * buffer[AZ_BLOCK_POS];
...@@ -379,6 +381,22 @@ void read_header(azio_stream *s, unsigned char *buffer) ...@@ -379,6 +381,22 @@ void read_header(azio_stream *s, unsigned char *buffer)
s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS); s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS);
s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS); s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS);
s->dirty= (unsigned int)buffer[AZ_DIRTY_POS]; s->dirty= (unsigned int)buffer[AZ_DIRTY_POS];
/*
we'll hard-code the current frm format for now, to avoid
changing archive table versions.
*/
if (s->frm_length == 0 ||
my_pread(s->file, tmp, sizeof(tmp), s->frm_start_pos + 64, MYF(MY_NABP)) ||
tmp[0] != 0 || tmp[1] != AZ_FRMVER_LEN)
{
s->frmver_length= 0;
}
else
{
s->frmver_length= tmp[1];
memcpy(s->frmver, tmp+2, s->frmver_length);
}
} }
else if (buffer[0] == gz_magic[0] && buffer[1] == gz_magic[1]) else if (buffer[0] == gz_magic[0] && buffer[1] == gz_magic[1])
{ {
......
...@@ -198,6 +198,7 @@ extern "C" { ...@@ -198,6 +198,7 @@ extern "C" {
#define AZ_BUFSIZE_READ 32768 #define AZ_BUFSIZE_READ 32768
#define AZ_BUFSIZE_WRITE 16384 #define AZ_BUFSIZE_WRITE 16384
#define AZ_FRMVER_LEN 16 /* same as MY_UUID_SIZE in 10.0.2 */
typedef struct azio_stream { typedef struct azio_stream {
z_stream stream; z_stream stream;
...@@ -227,6 +228,8 @@ typedef struct azio_stream { ...@@ -227,6 +228,8 @@ typedef struct azio_stream {
unsigned char dirty; /* State of file */ unsigned char dirty; /* State of file */
unsigned int frm_start_pos; /* Position for start of FRM */ unsigned int frm_start_pos; /* Position for start of FRM */
unsigned int frm_length; /* Position for start of FRM */ unsigned int frm_length; /* Position for start of FRM */
unsigned char frmver[AZ_FRMVER_LEN];
unsigned int frmver_length;
unsigned int comment_start_pos; /* Position for start of comment */ unsigned int comment_start_pos; /* Position for start of comment */
unsigned int comment_length; /* Position for start of comment */ unsigned int comment_length; /* Position for start of comment */
} azio_stream; } azio_stream;
......
...@@ -673,33 +673,12 @@ int ha_archive::frm_copy(azio_stream *src, azio_stream *dst) ...@@ -673,33 +673,12 @@ int ha_archive::frm_copy(azio_stream *src, azio_stream *dst)
int ha_archive::frm_compare(azio_stream *s) int ha_archive::frm_compare(azio_stream *s)
{ {
int rc= 0; if (!s->frmver_length)
const uchar *frm_ptr= 0; return 0; // Old pre-10.0 archive table. Never rediscover.
uchar *azfrm_ptr= 0;
size_t frm_len;
/* no frm = no discovery. perhaps it's a partitioned table */
if (table->s->read_frm_image(&frm_ptr, &frm_len))
goto err;
if (!(azfrm_ptr= (uchar *) my_malloc(s->frm_length,
MYF(MY_THREAD_SPECIFIC | MY_WME))))
goto err;
rc= 1;
if (frm_len != s->frm_length)
goto err;
if (azread_frm(s, azfrm_ptr))
goto err;
rc= memcmp(frm_ptr, azfrm_ptr, frm_len); LEX_CUSTRING *ver= &table->s->tabledef_version;
return ver->length != s->frmver_length ||
err: memcmp(ver->str, s->frmver, ver->length);
my_free(const_cast<uchar*>(frm_ptr));
my_free(azfrm_ptr);
return rc;
} }
......
--- suite/archive/discover.result 2013-04-08 00:06:37.000000000 +0200
+++ /usr/home/serg/Abk/mysql/10.0-serg/storage/test_sql_discovery/mysql-test/archive/discover.reject 2013-04-08 00:07:02.000000000 +0200
@@ -42,6 +42,7 @@
t1 BASE TABLE
t2 BASE TABLE
t1.ARZ
+t1.frm
t2.ARZ
t2.frm
#
@@ -60,6 +61,7 @@
flush tables;
rename table t2 to t0;
t0.ARZ
+t0.frm
t1.ARZ
t1.frm
#
@@ -77,6 +79,7 @@
flush tables;
drop table t1;
t0.ARZ
+t0.frm
#
# discover of table non-existance on drop
#
@@ -86,7 +89,7 @@
drop table t0;
show status like 'Handler_discover';
Variable_name Value
-Handler_discover 7
+Handler_discover 8
#
# Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE
#
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment