MySQL 读取 frm 源码

来源:互联网 发布:网络盒子看电视不清晰 编辑:程序博客网 时间:2024/05/21 22:38

static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,                           File file){  int error, errarg= 0;  uint new_frm_ver, field_pack_length, new_field_pack_flag;  uint interval_count, interval_parts, read_length, int_length;  uint db_create_options, keys, key_parts, n_length;  uint key_info_length, com_length, null_bit_pos, gcol_screen_length;  uint extra_rec_buf_length;  uint i,j;  bool use_extended_sk;   // Supported extending of secondary keys with PK parts  bool use_hash;  char *keynames, *names, *comment_pos, *gcol_screen_pos;  char *orig_comment_pos, *orig_gcol_screen_pos;  uchar forminfo[288];  uchar *record;  uchar *disk_buff, *strpos, *null_flags, *null_pos;  ulong pos, record_offset, *rec_per_key, rec_buff_length;  rec_per_key_t *rec_per_key_float;  handler *handler_file= 0;  KEY*keyinfo;  KEY_PART_INFO *key_part;  Field  **field_ptr;  const char **interval_array;  enum legacy_db_type legacy_db_type;  my_bitmap_map *bitmaps;  uchar *extra_segment_buff= 0;  const uint format_section_header_size= 8;  uchar *format_section_fields= 0;  bool has_vgc= false;  DBUG_ENTER("open_binary_frm");  new_field_pack_flag= head[27];  new_frm_ver= (head[2] - FRM_VER);  field_pack_length= new_frm_ver < 2 ? 11 : 17;  disk_buff= 0;  error= 3;  /* Position of the form in the form file. */  if (!(pos= get_form_pos(file, head)))    goto err;                                   /* purecov: inspected */  mysql_file_seek(file,pos,MY_SEEK_SET,MYF(0));  if (mysql_file_read(file, forminfo,288,MYF(MY_NABP)))    goto err;  share->frm_version= head[2];  /*    Check if .frm file created by MySQL 5.0. In this case we want to    display CHAR fields as CHAR and not as VARCHAR.    We do it this way as we want to keep the old frm version to enable    MySQL 4.1 to read these files.  */  if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5)    share->frm_version= FRM_VER_TRUE_VARCHAR;  if (*(head+61) &&      !(share->default_part_db_type=         ha_checktype(thd, (enum legacy_db_type) (uint) *(head+61), 1, 0)))    goto err;  DBUG_PRINT("info", ("default_part_db_type = %u", head[61]));  legacy_db_type= (enum legacy_db_type) (uint) *(head+3);  DBUG_ASSERT(share->db_plugin == NULL);  /*    if the storage engine is dynamic, no point in resolving it by its    dynamically allocated legacy_db_type. We will resolve it later by name.  */  if (legacy_db_type > DB_TYPE_UNKNOWN &&       legacy_db_type < DB_TYPE_FIRST_DYNAMIC)    share->db_plugin= ha_lock_engine(NULL,                                      ha_checktype(thd, legacy_db_type, 0, 0));  share->db_create_options= db_create_options= uint2korr(head+30);  share->db_options_in_use= share->db_create_options;  share->mysql_version= uint4korr(head+51);  share->null_field_first= 0;  if (!head[32])// New frm file in 3.23  {    share->avg_row_length= uint4korr(head+34);    share->row_type= (row_type) head[40];    share->table_charset= get_charset((((uint) head[41]) << 8) +                                         (uint) head[38],MYF(0));    share->null_field_first= 1;    share->stats_sample_pages= uint2korr(head+42);    share->stats_auto_recalc= static_cast<enum_stats_auto_recalc>(head[44]);  }  if (!share->table_charset)  {    /* unknown charset in head[38] or pre-3.23 frm */    if (use_mb(default_charset_info))    {      /* Warn that we may be changing the size of character columns */      sql_print_warning("'%s' had no or invalid character set, "                        "and default character set is multi-byte, "                        "so character column sizes may have changed",                        share->path.str);    }    share->table_charset= default_charset_info;  }  share->db_record_offset= 1;  /* Set temporarily a good value for db_low_byte_first */  share->db_low_byte_first= MY_TEST(legacy_db_type != DB_TYPE_ISAM);  error=4;  share->max_rows= uint4korr(head+18);  share->min_rows= uint4korr(head+22);  /* Read keyinformation */  key_info_length= (uint) uint2korr(head+28);  mysql_file_seek(file, (ulong) uint2korr(head+6), MY_SEEK_SET, MYF(0));  if (read_string(file, &disk_buff,key_info_length))    goto err;                                   /* purecov: inspected */  if (disk_buff[0] & 0x80)  {    share->keys=      keys=      (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);    share->key_parts= key_parts= uint2korr(disk_buff+2);  }  else  {    share->keys=      keys=      disk_buff[0];    share->key_parts= key_parts= disk_buff[1];  }  share->keys_for_keyread.init(0);  share->keys_in_use.init(keys);  strpos=disk_buff+6;    use_extended_sk=    ha_check_storage_engine_flag(share->db_type(),                                 HTON_SUPPORTS_EXTENDED_KEYS);  uint total_key_parts;  if (use_extended_sk)  {    uint primary_key_parts= keys ?      (new_frm_ver >= 3) ? (uint) strpos[4] : (uint) strpos[3] : 0;    total_key_parts= key_parts + primary_key_parts * (keys - 1);  }  else    total_key_parts= key_parts;  n_length= keys * sizeof(KEY) + total_key_parts * sizeof(KEY_PART_INFO);  /*    Allocate memory for the KEY object, the key part array, and the    two rec_per_key arrays.  */  if (!multi_alloc_root(&share->mem_root,                         &keyinfo, n_length + uint2korr(disk_buff + 4),                        &rec_per_key, sizeof(ulong) * total_key_parts,                        &rec_per_key_float,                        sizeof(rec_per_key_t) * total_key_parts,                        NULL))    goto err;                                   /* purecov: inspected */  memset(keyinfo, 0, n_length);  share->key_info= keyinfo;  key_part= reinterpret_cast<KEY_PART_INFO*>(keyinfo+keys);  for (i=0 ; i < keys ; i++, keyinfo++)  {    keyinfo->table= 0;                           // Updated in open_frm    if (new_frm_ver >= 3)    {      keyinfo->flags=   (uint) uint2korr(strpos) ^ HA_NOSAME;      keyinfo->key_length= (uint) uint2korr(strpos+2);      keyinfo->user_defined_key_parts= (uint) strpos[4];      keyinfo->algorithm=  (enum ha_key_alg) strpos[5];      keyinfo->block_size= uint2korr(strpos+6);      strpos+=8;    }    else    {      keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME;      keyinfo->key_length= (uint) uint2korr(strpos+1);      keyinfo->user_defined_key_parts= (uint) strpos[3];      keyinfo->algorithm= HA_KEY_ALG_UNDEF;      strpos+=4;    }    keyinfo->key_part= key_part;    keyinfo->set_rec_per_key_array(rec_per_key, rec_per_key_float);    keyinfo->set_in_memory_estimate(IN_MEMORY_ESTIMATE_UNKNOWN);    for (j=keyinfo->user_defined_key_parts ; j-- ; key_part++)    {      *rec_per_key++ = 0;      *rec_per_key_float++ = REC_PER_KEY_UNKNOWN;      key_part->fieldnr=(uint16) (uint2korr(strpos) & FIELD_NR_MASK);      key_part->offset= (uint) uint2korr(strpos+2)-1;      key_part->key_type=(uint) uint2korr(strpos+5);      // key_part->field=(Field*) 0;// Will be fixed later      if (new_frm_ver >= 1)      {key_part->key_part_flag= *(strpos+4);key_part->length=(uint) uint2korr(strpos+7);strpos+=9;      }      else      {key_part->length=*(strpos+4);key_part->key_part_flag=0;if (key_part->length > 128){  key_part->length&=127;/* purecov: inspected */  key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */}strpos+=7;      }      key_part->store_length=key_part->length;    }    /*      Add primary key parts if engine supports primary key extension for      secondary keys. Here we add unique first key parts to the end of      secondary key parts array and increase actual number of key parts.      Note that primary key is always first if exists. Later if there is no      primary key in the table then number of actual keys parts is set to      user defined key parts.    */    keyinfo->actual_key_parts= keyinfo->user_defined_key_parts;    keyinfo->actual_flags= keyinfo->flags;    if (use_extended_sk && i && !(keyinfo->flags & HA_NOSAME))    {      const uint primary_key_parts= share->key_info->user_defined_key_parts;      keyinfo->unused_key_parts= primary_key_parts;      key_part+= primary_key_parts;      rec_per_key+= primary_key_parts;      rec_per_key_float+= primary_key_parts;      share->key_parts+= primary_key_parts;    }  }  keynames=(char*) key_part;  strpos+= (my_stpcpy(keynames, (char *) strpos) - keynames)+1;  //reading index comments  for (keyinfo= share->key_info, i=0; i < keys; i++, keyinfo++)  {    if (keyinfo->flags & HA_USES_COMMENT)    {      keyinfo->comment.length= uint2korr(strpos);      keyinfo->comment.str= strmake_root(&share->mem_root, (char*) strpos+2,                                         keyinfo->comment.length);      strpos+= 2 + keyinfo->comment.length;    }     DBUG_ASSERT(MY_TEST(keyinfo->flags & HA_USES_COMMENT) ==               (keyinfo->comment.length > 0));  }  share->reclength = uint2korr((head+16));  share->stored_rec_length= share->reclength;  if (*(head+26) == 1)    share->system= 1;/* one-record-database */  record_offset= (ulong) (uint2korr(head+6)+                          ((uint2korr(head+14) == 0xffff ?                            uint4korr(head+47) : uint2korr(head+14))));   if ((n_length= uint4korr(head+55)))  {    /* Read extra data segment */    uchar *next_chunk, *buff_end;    DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));    if (!(extra_segment_buff= (uchar*) my_malloc(key_memory_frm_extra_segment_buff,                                                 n_length, MYF(MY_WME))))      goto err;    next_chunk= extra_segment_buff;    if (mysql_file_pread(file, extra_segment_buff,                         n_length, record_offset + share->reclength,                         MYF(MY_NABP)))    {      goto err;    }    share->connect_string.length= uint2korr(next_chunk);    if (!(share->connect_string.str= strmake_root(&share->mem_root,                                                  (char*) next_chunk + 2,                                                  share->connect_string.                                                  length)))    {      goto err;    }    next_chunk+= share->connect_string.length + 2;    buff_end= extra_segment_buff + n_length;    if (next_chunk + 2 < buff_end)    {      uint str_db_type_length= uint2korr(next_chunk);      LEX_STRING name;      name.str= (char*) next_chunk + 2;      name.length= str_db_type_length;      plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name, FALSE);      if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, share->db_plugin))      {        if (legacy_db_type > DB_TYPE_UNKNOWN &&            legacy_db_type < DB_TYPE_FIRST_DYNAMIC &&            legacy_db_type !=            ha_legacy_type(plugin_data<handlerton*>(tmp_plugin)))        {          /* bad file, legacy_db_type did not match the name */          goto err;        }        /*          tmp_plugin is locked with a local lock.          we unlock the old value of share->db_plugin before          replacing it with a globally locked version of tmp_plugin        */        plugin_unlock(NULL, share->db_plugin);        share->db_plugin= my_plugin_lock(NULL, &tmp_plugin);        DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",                            str_db_type_length, next_chunk + 2,                            ha_legacy_type(share->db_type())));      }      else if (!tmp_plugin && str_db_type_length == 9 &&               !strncmp((char *) next_chunk + 2, "partition", 9))      {        /* Check if the partitioning engine is ready */        if (!ha_checktype(thd, DB_TYPE_PARTITION_DB, true, false))        {          error= 8;          my_error(ER_FEATURE_NOT_AVAILABLE, MYF(0), "partitioning",                   "--skip-partition", "-DWITH_PARTITION_STORAGE_ENGINE=1");          goto err;        }/*          Partition engine is ready, share->db_plugin must already contain a          properly locked reference to it.        */DBUG_ASSERT(is_ha_partition_handlerton(plugin_data<handlerton*>(                                                 share->db_plugin)));        DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",                            str_db_type_length, next_chunk + 2,                            ha_legacy_type(share->db_type())));      }      else if (!tmp_plugin && name.length == 18 &&               !strncmp(name.str, "PERFORMANCE_SCHEMA", name.length))      {        /*          A FRM file is present on disk,          for a PERFORMANCE_SCHEMA table,          but this server binary is not compiled with the performance_schema,          as ha_resolve_by_name() did not find the storage engine.          This can happen:          - (a) during tests with mysql-test-run,            because the same database installed image is used            for regular builds (with P_S) and embedded builds (without P_S)          - (b) in production, when random binaries (without P_S) are thrown            on top of random installed database instances on disk (with P_S).          For the sake of robustness, pretend the table simply does not exist,          so that in particular it does not pollute the information_schema          with errors when scanning the disk for FRM files.          Note that ER_NO_SUCH_TABLE has a special treatment          in fill_schema_table_by_open()        */        error= 1;        my_error(ER_NO_SUCH_TABLE, MYF(0), share->db.str, share->table_name.str);        goto err;      }      else if (!tmp_plugin)      {        /* purecov: begin inspected */        error= 8;        name.str[name.length]=0;        my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);        goto err;        /* purecov: end */      }      next_chunk+= str_db_type_length + 2;    }    if (next_chunk + 5 < buff_end)    {      uint32 partition_info_str_len = uint4korr(next_chunk);      if ((share->partition_info_buffer_size=             share->partition_info_str_len= partition_info_str_len))      {        if (!(share->partition_info_str= (char*)              memdup_root(&share->mem_root, next_chunk + 4,                          partition_info_str_len + 1)))        {          goto err;        }      }      next_chunk+= 5 + partition_info_str_len;    }    if (share->mysql_version >= 50110 && next_chunk < buff_end)    {      /* New auto_partitioned indicator introduced in 5.1.11 */      share->auto_partitioned= *next_chunk;      next_chunk++;    }    keyinfo= share->key_info;    for (i= 0; i < keys; i++, keyinfo++)    {      if (keyinfo->flags & HA_USES_PARSER)      {        if (next_chunk >= buff_end)        {          DBUG_PRINT("error",                     ("fulltext key uses parser that is not defined in .frm"));          goto err;        }        LEX_CSTRING parser_name= {reinterpret_cast<char*>(next_chunk),                                  strlen(reinterpret_cast<char*>(next_chunk))};        next_chunk+= parser_name.length + 1;        keyinfo->parser= my_plugin_lock_by_name(NULL, parser_name,                                                MYSQL_FTPARSER_PLUGIN);        if (! keyinfo->parser)        {          my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str);          goto err;        }      }    }    if (forminfo[46] == (uchar)255)    {      //reading long table comment      if (next_chunk + 2 > buff_end)      {          DBUG_PRINT("error",                     ("long table comment is not defined in .frm"));          goto err;      }      share->comment.length = uint2korr(next_chunk);      if (! (share->comment.str= strmake_root(&share->mem_root,             (char*)next_chunk + 2, share->comment.length)))      {          goto err;      }      next_chunk+= 2 + share->comment.length;    }    if (next_chunk + format_section_header_size < buff_end)    {      /*        New extra data segment called "format section" with additional        table and column properties introduced by MySQL Cluster        based on 5.1.20        Table properties:        TABLESPACE <ts> and STORAGE [DISK|MEMORY]        Column properties:        COLUMN_FORMAT [DYNAMIC|FIXED] and STORAGE [DISK|MEMORY]      */      DBUG_PRINT("info", ("Found format section"));      /* header */      const uint format_section_length= uint2korr(next_chunk);      const uint format_section_flags= uint4korr(next_chunk+2);      /* 2 bytes unused */      if (next_chunk + format_section_length > buff_end)      {        DBUG_PRINT("error", ("format section length too long: %u",                             format_section_length));        goto err;      }      DBUG_PRINT("info", ("format_section_length: %u, format_section_flags: %u",                          format_section_length, format_section_flags));      share->default_storage_media=        (enum ha_storage_media) (format_section_flags & 0x7);      /* tablespace */      const char *tablespace=        (const char*)next_chunk + format_section_header_size;      const size_t tablespace_length= strlen(tablespace);      share->tablespace= NULL;      if (tablespace_length)      {        Tablespace_name_error_handler error_handler;        thd->push_internal_handler(&error_handler);        enum_ident_name_check name_check= check_tablespace_name(tablespace);        thd->pop_internal_handler();        if (name_check == IDENT_NAME_OK &&          !(share->tablespace= strmake_root(&share->mem_root,                                            tablespace, tablespace_length+1)))        {          goto err;        }      }      DBUG_PRINT("info", ("tablespace: '%s'",                          share->tablespace ? share->tablespace : "<null>"));      /* pointer to format section for fields */      format_section_fields=        next_chunk + format_section_header_size + tablespace_length + 1;      next_chunk+= format_section_length;    }    if (next_chunk + 2 <= buff_end)    {      share->compress.length = uint2korr(next_chunk);      if (! (share->compress.str= strmake_root(&share->mem_root,             (char*)next_chunk + 2, share->compress.length)))      {          goto err;      }      next_chunk+= 2 + share->compress.length;    }    if (next_chunk + 2 <= buff_end)    {      share->encrypt_type.length = uint2korr(next_chunk);      if (! (share->encrypt_type.str= strmake_root(&share->mem_root,             (char*)next_chunk + 2, share->encrypt_type.length)))      {          goto err;      }      next_chunk+= 2 + share->encrypt_type.length;    }  }  share->key_block_size= uint2korr(head+62);  error=4;  extra_rec_buf_length= uint2korr(head+59);  rec_buff_length= ALIGN_SIZE(share->reclength + 1 + extra_rec_buf_length);  share->rec_buff_length= rec_buff_length;  if (!(record= (uchar *) alloc_root(&share->mem_root,                                     rec_buff_length)))    goto err;                                   /* purecov: inspected */  share->default_values= record;  if (mysql_file_pread(file, record, (size_t) share->reclength,                       record_offset, MYF(MY_NABP)))    goto err;                                   /* purecov: inspected */  mysql_file_seek(file, pos+288, MY_SEEK_SET, MYF(0));  share->fields= uint2korr(forminfo+258);  pos= uint2korr(forminfo+260);   /* Length of all screens */  n_length= uint2korr(forminfo+268);  interval_count= uint2korr(forminfo+270);  interval_parts= uint2korr(forminfo+272);  int_length= uint2korr(forminfo+274);  share->null_fields= uint2korr(forminfo+282);  com_length= uint2korr(forminfo+284);  gcol_screen_length= uint2korr(forminfo+286);  share->vfields= 0;  share->stored_fields= share->fields;  if (forminfo[46] != (uchar)255)  {    share->comment.length=  (int) (forminfo[46]);    share->comment.str= strmake_root(&share->mem_root, (char*) forminfo+47,                                     share->comment.length);  }  DBUG_PRINT("info",("i_count: %d  i_parts: %d  index: %d  n_length: %d  int_length: %d  com_length: %d  gcol_screen_length: %d", interval_count,interval_parts, share->keys,n_length,int_length, com_length, gcol_screen_length));  if (!(field_ptr = (Field **)alloc_root(&share->mem_root,   (uint) ((share->fields+1)*sizeof(Field*)+   interval_count*sizeof(TYPELIB)+   (share->fields+interval_parts+    keys+3)*sizeof(char *)+   (n_length+int_length+com_length+       gcol_screen_length)))))    goto err;                                   /* purecov: inspected */  share->field= field_ptr;  read_length=(uint) (share->fields * field_pack_length +      pos+ (uint) (n_length+int_length+com_length+                   gcol_screen_length));  if (read_string(file, &disk_buff,read_length))    goto err;                                   /* purecov: inspected */  strpos= disk_buff+pos;  share->intervals= (TYPELIB*) (field_ptr+share->fields+1);  interval_array= (const char **) (share->intervals+interval_count);  names= (char*) (interval_array+share->fields+interval_parts+keys+3);  if (!interval_count)    share->intervals= 0;// For better debugging  memcpy(names, strpos+(share->fields*field_pack_length), (uint) (n_length+int_length));  orig_comment_pos= comment_pos= names+(n_length+int_length);  memcpy(comment_pos, disk_buff+read_length-com_length-gcol_screen_length,          com_length);  orig_gcol_screen_pos= gcol_screen_pos= names+(n_length+int_length+com_length);  memcpy(gcol_screen_pos, disk_buff+read_length-gcol_screen_length,          gcol_screen_length);  fix_type_pointers(&interval_array, &share->fieldnames, 1, &names);  if (share->fieldnames.count != share->fields)    goto err;  fix_type_pointers(&interval_array, share->intervals, interval_count,    &names);  {    /* Set ENUM and SET lengths */    TYPELIB *interval;    for (interval= share->intervals;         interval < share->intervals + interval_count;         interval++)    {      uint count= (uint) (interval->count + 1) * sizeof(uint);      if (!(interval->type_lengths= (uint *) alloc_root(&share->mem_root,                                                        count)))        goto err;      for (count= 0; count < interval->count; count++)      {        char *val= (char*) interval->type_names[count];        interval->type_lengths[count]= strlen(val);      }      interval->type_lengths[count]= 0;    }  }  if (keynames)    fix_type_pointers(&interval_array, &share->keynames, 1, &keynames); /* Allocate handler */  if (!(handler_file= get_new_handler(share, thd->mem_root,                                      share->db_type())))    goto err;  if (handler_file->set_ha_share_ref(&share->ha_share))    goto err;  if (share->null_field_first)  {    null_flags= null_pos= share->default_values;    null_bit_pos= (db_create_options & HA_OPTION_PACK_RECORD) ? 0 : 1;    /*      null_bytes below is only correct under the condition that      there are no bit fields.  Correct values is set below after the      table struct is initialized    */    share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;  }  else  {    share->null_bytes= (share->null_fields+7)/8;    null_flags= null_pos= share->default_values + share->reclength -                          share->null_bytes;    null_bit_pos= 0;  }  use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;  if (use_hash)    use_hash= !my_hash_init(&share->name_hash,                            system_charset_info,                            share->fields,0,0,                            (my_hash_get_key) get_field_name,0,0,                            PSI_INSTRUMENT_ME);  for (i=0 ; i < share->fields; i++, strpos+=field_pack_length)  {    if (new_frm_ver >= 3 &&        (strpos[10] & Field::GENERATED_FIELD) && // Field::unireg_check        ! (bool) (uint) (gcol_screen_pos[3]))    // Field::stored_in_db    {      /*        Skip virtual generated columns as we will do separate pass for them.        We still need to advance pointers to current comment and generated        column info in for such fields.      */      comment_pos+= uint2korr(strpos+15);      gcol_screen_pos+= uint2korr(gcol_screen_pos + 1) + FRM_GCOL_HEADER_SIZE;      has_vgc= true;    }    else    {      if ((error= make_field_from_frm(thd, share,                                      new_frm_ver, use_hash,                                      i, strpos,                                      format_section_fields,                                      &comment_pos,                                      &gcol_screen_pos,                                      &null_pos,                                      &null_bit_pos,                                      &errarg)))        goto err;    }  }  if (has_vgc)  {    /*      We need to do separate pass through field descriptions for virtual      generated columns to ensure that they get allocated null/leftover      bits at the tail of record preamble.    */    strpos= disk_buff+pos;    comment_pos= orig_comment_pos;    gcol_screen_pos= orig_gcol_screen_pos;    // Generated columns can be present only in new .FRMs.    DBUG_ASSERT(new_frm_ver >= 3);    for (i=0 ; i < share->fields; i++, strpos+=field_pack_length)    {      if ((strpos[10] & Field::GENERATED_FIELD) && // Field::unireg_check          !(bool) (uint) (gcol_screen_pos[3]))     // Field::stored_in_db      {        if ((error= make_field_from_frm(thd, share,                                        new_frm_ver, use_hash,                                        i, strpos,                                        format_section_fields,                                        &comment_pos,                                        &gcol_screen_pos,                                        &null_pos,                                        &null_bit_pos,                                        &errarg)))          goto err;      }      else      {        /*          Advance pointers to current comment and generated columns          info for stored fields.        */        comment_pos+= uint2korr(strpos+15);        if (strpos[10] & Field::GENERATED_FIELD) // Field::unireg_check        {          gcol_screen_pos+= uint2korr(gcol_screen_pos + 1) +                            FRM_GCOL_HEADER_SIZE;        }      }    }  }  error= 4;  share->field[share->fields]= 0; // End marker  /* Sanity checks: */  DBUG_ASSERT(share->fields >= share->stored_fields);  DBUG_ASSERT(share->reclength >= share->stored_rec_length);  /* Fix key->name and key_part->field */  if (key_parts)  {    const int pk_off= find_type(primary_key_name, &share->keynames,                                  FIND_TYPE_NO_PREFIX);    uint primary_key= (pk_off > 0 ? pk_off-1 : MAX_KEY);    longlong ha_option= handler_file->ha_table_flags();    keyinfo= share->key_info;    key_part= keyinfo->key_part;    for (uint key=0 ; key < share->keys ; key++,keyinfo++)    {      uint usable_parts= 0;      keyinfo->name=(char*) share->keynames.type_names[key];      /* Fix fulltext keys for old .frm files */      if (share->key_info[key].flags & HA_FULLTEXT)share->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;      if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))      {/*  If the UNIQUE key doesn't have NULL columns and is not a part key  declare this as a primary key.*/primary_key=key;for (i=0 ; i < keyinfo->user_defined_key_parts ;i++){          DBUG_ASSERT(key_part[i].fieldnr > 0);          // Table field corresponding to the i'th key part.          Field *table_field= share->field[key_part[i].fieldnr - 1];          // Index on virtual generated columns is not allowed to be PK          // even when the conditions below are true, so this case must be          // rejected here.          if (table_field->is_virtual_gcol())          {            primary_key= MAX_KEY;// Can't be used            break;          }          /*            If the key column is of NOT NULL BLOB type, then it            will definitly have key prefix. And if key part prefix size            is equal to the BLOB column max size, then we can promote            it to primary key.          */          if (!table_field->real_maybe_null() &&              table_field->type() == MYSQL_TYPE_BLOB &&              table_field->field_length == key_part[i].length)            continue;          /*            If the key column is of NOT NULL GEOMETRY type, specifically POINT            type whose length is known internally (which is 25). And key part            prefix size is equal to the POINT column max size, then we can            promote it to primary key.          */          if (!table_field->real_maybe_null() &&              table_field->type() == MYSQL_TYPE_GEOMETRY &&              table_field->get_geometry_type() == Field::GEOM_POINT &&              key_part[i].length == MAX_LEN_GEOM_POINT_FIELD)            continue;  if (table_field->real_maybe_null() ||      table_field->key_length() != key_part[i].length)   {    primary_key= MAX_KEY;// Can't be used    break;  }}      }      for (i=0 ; i < keyinfo->user_defined_key_parts ; key_part++,i++)      {        Field *field;if (new_field_pack_flag <= 1)  key_part->fieldnr= (uint16) find_field(share->field,                                                 share->default_values,                                                 (uint) key_part->offset,                                                 (uint) key_part->length);if (!key_part->fieldnr)        {          error= 4;                             // Wrong file          goto err;        }        field= key_part->field= share->field[key_part->fieldnr-1];        key_part->type= field->key_type();        if (field->real_maybe_null())        {          key_part->null_offset=field->null_offset(share->default_values);          key_part->null_bit= field->null_bit;          key_part->store_length+=HA_KEY_NULL_LENGTH;          keyinfo->flags|=HA_NULL_PART_KEY;          keyinfo->key_length+= HA_KEY_NULL_LENGTH;        }        if (field->type() == MYSQL_TYPE_BLOB ||            field->real_type() == MYSQL_TYPE_VARCHAR ||            field->type() == MYSQL_TYPE_GEOMETRY)        {          key_part->store_length+=HA_KEY_BLOB_LENGTH;          if (i + 1 <= keyinfo->user_defined_key_parts)            keyinfo->key_length+= HA_KEY_BLOB_LENGTH;        }        key_part->init_flags();        if (field->is_virtual_gcol())          keyinfo->flags|= HA_VIRTUAL_GEN_KEY;        setup_key_part_field(share, handler_file, primary_key,                             keyinfo, key, i, &usable_parts);        field->flags|= PART_KEY_FLAG;        if (key == primary_key)        {          field->flags|= PRI_KEY_FLAG;          /*            If this field is part of the primary key and all keys contains            the primary key, then we can use any key to find this column          */          if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)          {            if (field->key_length() == key_part->length &&                !(field->flags & BLOB_FLAG))              field->part_of_key= share->keys_in_use;            if (field->part_of_sortkey.is_set(key))              field->part_of_sortkey= share->keys_in_use;          }        }        if (field->key_length() != key_part->length)        {          if (field->type() == MYSQL_TYPE_NEWDECIMAL)          {            /*              Fix a fatal error in decimal key handling that causes crashes              on Innodb. We fix it by reducing the key length so that              InnoDB never gets a too big key when searching.              This allows the end user to do an ALTER TABLE to fix the              error.            */            keyinfo->key_length-= (key_part->length - field->key_length());            key_part->store_length-= (uint16)(key_part->length -                                              field->key_length());            key_part->length= (uint16)field->key_length();            sql_print_error("Found wrong key definition in %s; "                            "Please do \"ALTER TABLE `%s` FORCE \" to fix it!",                            share->table_name.str,                            share->table_name.str);            push_warning_printf(thd, Sql_condition::SL_WARNING,                                ER_CRASHED_ON_USAGE,                                "Found wrong key definition in %s; "                                "Please do \"ALTER TABLE `%s` FORCE\" to fix "                                "it!",                                share->table_name.str,                                share->table_name.str);            share->crashed= 1;                // Marker for CHECK TABLE            continue;          }          key_part->key_part_flag|= HA_PART_KEY_SEG;        }      }      if (use_extended_sk && primary_key < MAX_KEY &&          key && !(keyinfo->flags & HA_NOSAME))        key_part+= add_pk_parts_to_sk(keyinfo, key, share->key_info, primary_key,                                      share,  handler_file, &usable_parts);      /* Skip unused key parts if they exist */      key_part+= keyinfo->unused_key_parts;      keyinfo->usable_key_parts= usable_parts; // Filesort      set_if_bigger(share->max_key_length,keyinfo->key_length+                    keyinfo->user_defined_key_parts);      share->total_key_length+= keyinfo->key_length;      /*        MERGE tables do not have unique indexes. But every key could be        an unique index on the underlying MyISAM table. (Bug #10400)      */      if ((keyinfo->flags & HA_NOSAME) ||          (ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE))        set_if_bigger(share->max_unique_length,keyinfo->key_length);    }    if (primary_key < MAX_KEY &&(share->keys_in_use.is_set(primary_key)))    {      share->primary_key= primary_key;      /*If we are using an integer as the primary key then allow the user torefer to it as '_rowid'      */      if (share->key_info[primary_key].user_defined_key_parts == 1)      {Field *field= share->key_info[primary_key].key_part[0].field;if (field && field->result_type() == INT_RESULT)        {          /* note that fieldnr here (and rowid_field_offset) starts from 1 */  share->rowid_field_offset= (share->key_info[primary_key].key_part[0].                                      fieldnr);        }      }    }    else      share->primary_key = MAX_KEY; // we do not have a primary key  }  else    share->primary_key= MAX_KEY;  my_free(disk_buff);  disk_buff=0;  if (new_field_pack_flag <= 1)  {    /* Old file format with default as not null */    uint null_length= (share->null_fields+7)/8;    memset(share->default_values + (null_flags - record), 255,           null_length);  }  if (share->found_next_number_field)  {    Field *reg_field= *share->found_next_number_field;    if ((int) (share->next_number_index= (uint)       find_ref_key(share->key_info, share->keys,                            share->default_values, reg_field,    &share->next_number_key_offset,                            &share->next_number_keypart)) < 0)    {      /* Wrong field definition */      error= 4;      goto err;    }    else      reg_field->flags |= AUTO_INCREMENT_FLAG;  }  if (share->blob_fields)  {    Field **ptr;    uint k, *save;    /* Store offsets to blob fields to find them fast */    if (!(share->blob_field= save=  (uint*) alloc_root(&share->mem_root,                             (uint) (share->blob_fields* sizeof(uint)))))      goto err;    for (k=0, ptr= share->field ; *ptr ; ptr++, k++)    {      if ((*ptr)->flags & BLOB_FLAG)(*save++)= k;    }  }  /*    the correct null_bytes can now be set, since bitfields have been taken    into account  */  share->null_bytes= (null_pos - null_flags +                      (null_bit_pos + 7) / 8);  share->last_null_bit_pos= null_bit_pos;  share->db_low_byte_first= handler_file->low_byte_first();  share->column_bitmap_size= bitmap_buffer_size(share->fields);  if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root,                                             share->column_bitmap_size)))    goto err;  bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);  bitmap_set_all(&share->all_set);  delete handler_file;#ifndef DBUG_OFF  if (use_hash)    (void) my_hash_check(&share->name_hash);#endif  my_free(extra_segment_buff);  DBUG_RETURN (0); err:  share->error= error;  share->open_errno= my_errno();  share->errarg= errarg;  my_free(disk_buff);  my_free(extra_segment_buff);  delete handler_file;  my_hash_free(&share->name_hash);  open_table_error(share, error, share->open_errno, errarg);  DBUG_RETURN(error);} /* open_binary_frm */

MySQL 底层实现