http://www.cnblogs.com/jiangxu67/p/4755097.html
http://www.cnblogs.com/jiangxu67/p/4755097.html
http://guduwhuzhe.iteye.com/blog/1887619
bool mysql_create_frm(THD *thd, const char *file_name, const char *db, const char *table, HA_CREATE_INFO *create_info, List<Create_field> &create_fields, uint keys, KEY *key_info, handler *db_file) { LEX_STRING str_db_type; uint reclength, info_length, screens, key_info_length, maxlength, tmp_len, i; ulong key_buff_length; File file; ulong filepos, data_offset; uchar fileinfo[64],forminfo[288],*keybuff; uchar *screen_buff; char buff[128]; Pack_header_error_handler pack_header_error_handler; int error; const uint format_section_header_size= 8; uint format_section_length; uint tablespace_length= 0; DBUG_ENTER("mysql_create_frm"); DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0))) DBUG_RETURN(1); DBUG_ASSERT(db_file != NULL); /* If fixed row records, we need one bit to check for deleted rows */ if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) create_info->null_bits++; data_offset= (create_info->null_bits + 7) / 8; thd->push_internal_handler(&pack_header_error_handler); error= pack_header(forminfo, ha_legacy_type(create_info->db_type), create_fields,info_length, screens, create_info->table_options, data_offset, db_file); thd->pop_internal_handler(); if (error) { my_free(screen_buff); } reclength=uint2korr(forminfo+266); /* Calculate extra data segment length */ str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type); str_db_type.length= strlen(str_db_type.str); /* str_db_type */ create_info->extra_size= (2 + str_db_type.length + 2 + create_info->connect_string.length); create_info->extra_size+= 6; /* If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes, store the comment in an extra segment (up to TABLE_COMMENT_MAXLEN bytes). Pre 6.0, the limit was 60 characters, with no extra segment-handling. */ if (create_info->comment.length > TABLE_COMMENT_INLINE_MAXLEN) { forminfo[46]=255; create_info->extra_size+= 2 + create_info->comment.length; } else{ strmake((char*) forminfo+47, create_info->comment.str ? create_info->comment.str : "", create_info->comment.length); forminfo[46]=(uchar) create_info->comment.length; } if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo, create_info, keys, key_info)) < 0) { my_free(screen_buff); DBUG_RETURN(1); } key_buff_length= uint4korr(fileinfo+47); keybuff=(uchar*) my_malloc(key_buff_length, MYF(0)); key_info_length= pack_keys(keybuff, keys, key_info, data_offset); /* Ensure that there are no forms in this newly created form file. Even if the form file exists, create_frm must truncate it to ensure one form per form file. */ DBUG_ASSERT(uint2korr(fileinfo+8) == 0); if (!(filepos= make_new_entry(file, fileinfo, NULL, ""))) goto err; maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000)); int2store(forminfo+2,maxlength); int4store(fileinfo+10,(ulong) (filepos+maxlength)); fileinfo[26]= (uchar) test((create_info->max_rows == 1) && (create_info->min_rows == 1) && (keys == 0)); int2store(fileinfo+28,key_info_length); int2store(fileinfo+59,db_file->extra_rec_buf_length()); if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) || mysql_file_pwrite(file, keybuff, key_info_length, (ulong) uint2korr(fileinfo+6), MYF_RW)) goto err; mysql_file_seek(file, (ulong) uint2korr(fileinfo+6) + (ulong) key_buff_length, MY_SEEK_SET, MYF(0)); if (make_empty_rec(thd,file,ha_legacy_type(create_info->db_type), create_info->table_options, create_fields,reclength, data_offset, db_file)) goto err; int2store(buff, create_info->connect_string.length); if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) || mysql_file_write(file, (const uchar*)create_info->connect_string.str, create_info->connect_string.length, MYF(MY_NABP))) goto err; int2store(buff, str_db_type.length); if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) || mysql_file_write(file, (const uchar*)str_db_type.str, str_db_type.length, MYF(MY_NABP))) goto err; { bzero((uchar*) buff, 6); if (mysql_file_write(file, (uchar*) buff, 6, MYF_RW)) goto err; } for (i= 0; i < keys; i++) { if (key_info[i].parser_name) { if (mysql_file_write(file, (const uchar*)key_info[i].parser_name->str, key_info[i].parser_name->length + 1, MYF(MY_NABP))) goto err; } } if (forminfo[46] == (uchar)255) { uchar comment_length_buff[2]; int2store(comment_length_buff,create_info->comment.length); if (mysql_file_write(file, comment_length_buff, 2, MYF(MY_NABP)) || mysql_file_write(file, (uchar*) create_info->comment.str, create_info->comment.length, MYF(MY_NABP))) goto err; } /* "Format section" with additional table and column properties */ mysql_file_seek(file, filepos, MY_SEEK_SET, MYF(0)); if (mysql_file_write(file, forminfo, 288, MYF_RW) || mysql_file_write(file, screen_buff, info_length, MYF_RW) || pack_fields(file, create_fields, data_offset)) goto err; my_free(screen_buff); my_free(keybuff); if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) && (mysql_file_sync(file, MYF(MY_WME)) || my_sync_dir_by_file(file_name, MYF(MY_WME)))) goto err2; if (mysql_file_close(file, MYF(MY_WME))) goto err3; err: my_free(screen_buff); my_free(keybuff); err2: (void) mysql_file_close(file, MYF(MY_WME)); err3: mysql_file_delete(key_file_frm, file_name, MYF(0)); DBUG_RETURN(1); } /* mysql_create_frm */
/* Pack keyinfo and keynames to keybuff for save in form-file. */ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo, ulong data_offset) { uint key_parts,length; uchar *pos, *keyname_pos; KEY *key,*end; KEY_PART_INFO *key_part,*key_part_end; DBUG_ENTER("pack_keys"); pos=keybuff+6; key_parts=0; for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++) { int2store(pos, (key->flags ^ HA_NOSAME)); int2store(pos+2,key->key_length); pos[4]= (uchar) key->key_parts; pos[5]= (uchar) key->algorithm; int2store(pos+6, key->block_size); pos+=8; key_parts+=key->key_parts; DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx", key->flags, key->key_parts, (long) key->key_part)); for (key_part=key->key_part,key_part_end=key_part+key->key_parts ; key_part != key_part_end ; key_part++) { uint offset; DBUG_PRINT("loop",("field: %d startpos: %lu length: %d", key_part->fieldnr, key_part->offset + data_offset, key_part->length)); int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED); offset= (uint) (key_part->offset+data_offset+1); int2store(pos+2, offset); pos[4]=0; // Sort order int2store(pos+5,key_part->key_type); int2store(pos+7,key_part->length); pos+=9; } } /* Save keynames */ keyname_pos=pos; *pos++=(uchar) NAMES_SEP_CHAR; for (key=keyinfo ; key != end ; key++) { uchar *tmp=(uchar*) strmov((char*) pos,key->name); *tmp++= (uchar) NAMES_SEP_CHAR; *tmp=0; pos=tmp; } *(pos++)=0; for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++) { if (key->flags & HA_USES_COMMENT) { int2store(pos, key->comment.length); uchar *tmp= (uchar*)strnmov((char*) pos+2,key->comment.str, key->comment.length); pos= tmp; } } if (key_count > 127 || key_parts > 127) { keybuff[0]= (key_count & 0x7f) | 0x80; keybuff[1]= key_count >> 7; int2store(keybuff+2,key_parts); } else { keybuff[0]=(uchar) key_count; keybuff[1]=(uchar) key_parts; keybuff[2]= keybuff[3]= 0; } length=(uint) (pos-keyname_pos); int2store(keybuff+4,length); DBUG_RETURN((uint) (pos-keybuff)); } /* pack_keys */
/* Save fields, fieldnames and intervals */ static bool pack_fields(File file, List<Create_field> &create_fields, ulong data_offset) { reg2 uint i; uint int_count, comment_length=0; uchar buff[MAX_FIELD_WIDTH]; Create_field *field; DBUG_ENTER("pack_fields"); /* Write field info */ List_iterator<Create_field> it(create_fields); int_count=0; while ((field=it++)) { uint recpos; buff[0]= (uchar) field->row; buff[1]= (uchar) field->col; buff[2]= (uchar) field->sc_length; int2store(buff+3, field->length); /* The +1 is here becasue the col offset in .frm file have offset 1 */ recpos= field->offset+1 + (uint) data_offset; int3store(buff+5,recpos); int2store(buff+8,field->pack_flag); DBUG_ASSERT(field->unireg_check < 256); buff[10]= (uchar) field->unireg_check; buff[12]= (uchar) field->interval_id; buff[13]= (uchar) field->sql_type; if (field->sql_type == MYSQL_TYPE_GEOMETRY) { buff[11]= 0; buff[14]= (uchar) field->geom_type; #ifndef HAVE_SPATIAL DBUG_ASSERT(0); // Should newer happen #endif } else if (field->charset) { buff[11]= (uchar) (field->charset->number >> 8); buff[14]= (uchar) field->charset->number; } else { buff[11]= buff[14]= 0; // Numerical } int2store(buff+15, field->comment.length); comment_length+= field->comment.length; set_if_bigger(int_count,field->interval_id); if (mysql_file_write(file, buff, FCOMP, MYF_RW)) DBUG_RETURN(1); } /* Write fieldnames */ buff[0]=(uchar) NAMES_SEP_CHAR; if (mysql_file_write(file, buff, 1, MYF_RW)) DBUG_RETURN(1); i=0; it.rewind(); while ((field=it++)) { char *pos= strmov((char*) buff,field->field_name); *pos++=NAMES_SEP_CHAR; if (i == create_fields.elements-1) *pos++=0; if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW)) DBUG_RETURN(1); i++; } /* Write intervals */ if (int_count) { String tmp((char*) buff,sizeof(buff), &my_charset_bin); tmp.length(0); it.rewind(); int_count=0; while ((field=it++)) { if (field->interval_id > int_count) { unsigned char sep= 0; unsigned char occ[256]; uint i; unsigned char *val= NULL; bzero(occ, sizeof(occ)); for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++) for (uint j = 0; j < field->interval->type_lengths[i]; j++) occ[(unsigned int) (val[j])]= 1; if (!occ[(unsigned char)NAMES_SEP_CHAR]) sep= (unsigned char) NAMES_SEP_CHAR; else if (!occ[(unsigned int)',']) sep= ','; else { for (uint i=1; i<256; i++) { if(!occ[i]) { sep= i; break; } } if(!sep) /* disaster, enum uses all characters, none left as separator */ { my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS), MYF(0)); DBUG_RETURN(1); } } int_count= field->interval_id; tmp.append(sep); for (const char **pos=field->interval->type_names ; *pos ; pos++) { tmp.append(*pos); tmp.append(sep); } tmp.append('\0'); // End of intervall } } if (mysql_file_write(file, (uchar*) tmp.ptr(), tmp.length(), MYF_RW)) DBUG_RETURN(1); } if (comment_length) { it.rewind(); int_count=0; while ((field=it++)) { if (field->comment.length) if (mysql_file_write(file, (uchar*) field->comment.str, field->comment.length, MYF_RW)) DBUG_RETURN(1); } } DBUG_RETURN(0); }