官网说明:http://dev.mysql.com/doc/internals/en/frm-file-format.html
frm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果出现特殊情况出现frm文件损坏也不要放弃希望,例如下面报错:
150821 16:31:27 [ERROR] /usr/local/mysql51/libexec/mysqld: Incorrect information in file: './t/test1.frm'
当修复MyISAM和InnoDB表时,MySQL服务会首先去调用frm文件,所以我们只能通过修复frm文件进行后面的数据恢复。
MySQL通过sql/table.cc的create_frm()函数创建frm文件,创建出来的frm文件是二进制文件,需要通过hexdump解析成16进制来分析。
create_frm()函数对frm文件头部定义的代码
/* Create a .frm file */ File create_frm(THD *thd, const char *name, const char *db, const char *table, uint reclength, uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys, KEY *key_info) { register File file; ulong length; uchar fill[IO_SIZE]; int create_flags= O_RDWR | O_TRUNC; ulong key_comment_total_bytes= 0; uint i; if (create_info->options & HA_LEX_CREATE_TMP_TABLE) create_flags|= O_EXCL | O_NOFOLLOW; /* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */ if (create_info->max_rows > UINT_MAX32) create_info->max_rows= UINT_MAX32; if (create_info->min_rows > UINT_MAX32) create_info->min_rows= UINT_MAX32; if ((file= mysql_file_create(key_file_frm, name, CREATE_MODE, create_flags, MYF(0))) >= 0) { uint key_length, tmp_key_length, tmp, csid; bzero((char*) fileinfo,64); /* header */ fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3+ test(create_info->varchar); fileinfo[3]= (uchar) ha_legacy_type( ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0)); fileinfo[4]=1; int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ /* Keep in sync with pack_keys() in unireg.cc For each key: 8 bytes for the key header 9 bytes for each key-part (MAX_REF_PARTS) NAME_LEN bytes for the name 1 byte for the NAMES_SEP_CHAR (before the name) For all keys: 6 bytes for the header 1 byte for the NAMES_SEP_CHAR (after the last name) 9 extra bytes (padding for safety? alignment?) */ for (i= 0; i < keys; i++) { DBUG_ASSERT(test(key_info[i].flags & HA_USES_COMMENT) == (key_info[i].comment.length > 0)); if (key_info[i].flags & HA_USES_COMMENT) key_comment_total_bytes += 2 + key_info[i].comment.length; } key_length= keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16 + key_comment_total_bytes; length= next_io_size((ulong) (IO_SIZE+key_length+reclength+ create_info->extra_size)); int4store(fileinfo+10,length); tmp_key_length= (key_length < 0xffff) ? key_length : 0xffff; int2store(fileinfo+14,tmp_key_length); int2store(fileinfo+16,reclength); int4store(fileinfo+18,create_info->max_rows); int4store(fileinfo+22,create_info->min_rows); /* fileinfo[26] is set in mysql_create_frm() */ fileinfo[27]=2; // Use long pack-fields /* fileinfo[28 & 29] is set to key_info_length in mysql_create_frm() */ create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers int2store(fileinfo+30,create_info->table_options); fileinfo[32]=0; // No filename anymore fileinfo[33]=5; // Mark for 5.0 frm file int4store(fileinfo+34,create_info->avg_row_length); csid= (create_info->default_table_charset ? create_info->default_table_charset->number : 0); fileinfo[38]= (uchar) csid; /* In future versions, we will store in fileinfo[39] the values of the TRANSACTIONAL and PAGE_CHECKSUM clauses of CREATE TABLE. */ fileinfo[39]= 0; fileinfo[40]= (uchar) create_info->row_type; /* Next few bytes where for RAID support */ fileinfo[41]= (uchar) (csid >> 8); fileinfo[42]= 0; fileinfo[43]= 0; fileinfo[44]= 0; fileinfo[45]= 0; fileinfo[46]= 0; int4store(fileinfo+47, key_length); tmp= MYSQL_VERSION_ID; // Store to avoid warning from int4store int4store(fileinfo+51, tmp); int4store(fileinfo+55, create_info->extra_size); /* 59-60 is reserved for extra_rec_buf_length, 61 for default_part_db_type */ int2store(fileinfo+62, create_info->key_block_size); bzero(fill,IO_SIZE); for (; length > IO_SIZE ; length-= IO_SIZE) { if (mysql_file_write(file, fill, IO_SIZE, MYF(MY_WME | MY_NABP))) { (void) mysql_file_close(file, MYF(0)); (void) mysql_file_delete(key_file_frm, name, MYF(0)); return(-1); } } } else { if (my_errno == ENOENT) my_error(ER_BAD_DB_ERROR,MYF(0),db); else my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno); } return (file); } /* create_frm */