Drizzled Public API Documentation

mi_open.cc
00001 /* Copyright (C) 2000-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /* open a isam-database */
00017 
00018 #include "myisam_priv.h"
00019 
00020 #include <string.h>
00021 #include <algorithm>
00022 #include <memory>
00023 #include <boost/scoped_ptr.hpp>
00024 #include <boost/scoped_array.hpp>
00025 
00026 #include <drizzled/internal/m_string.h>
00027 #include <drizzled/util/test.h>
00028 #include <drizzled/charset.h>
00029 #include <drizzled/memory/multi_malloc.h>
00030 #include <drizzled/identifier.h>
00031 
00032 
00033 using namespace std;
00034 using namespace drizzled;
00035 
00036 static void setup_key_functions(MI_KEYDEF *keyinfo);
00037 static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef);
00038 static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg);
00039 static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo);
00040 static uint64_t mi_safe_mul(uint64_t a, uint64_t b);
00041 static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state);
00042 static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def);
00043 static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base);
00044 
00045 #define disk_pos_assert(pos, end_pos) \
00046 if (pos > end_pos)             \
00047 {                              \
00048   errno=HA_ERR_CRASHED;     \
00049   goto err;                    \
00050 }
00051 
00052 
00053 /******************************************************************************
00054 ** Return the shared struct if the table is already open.
00055 ** In MySQL the server will handle version issues.
00056 ******************************************************************************/
00057 
00058 MI_INFO *test_if_reopen(char *filename)
00059 {
00060   list<MI_INFO *>::iterator it= myisam_open_list.begin();
00061   while (it != myisam_open_list.end())
00062   {
00063     MI_INFO *info= *it;
00064     MYISAM_SHARE *share=info->s;
00065     if (!strcmp(share->unique_file_name,filename) && share->last_version)
00066       return info;
00067     ++it;
00068   }
00069   return 0;
00070 }
00071 
00072 
00073 /******************************************************************************
00074   open a MyISAM database.
00075   See my_base.h for the handle_locking argument
00076   if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
00077   is marked crashed or if we are not using locking and the table doesn't
00078   have an open count of 0.
00079 ******************************************************************************/
00080 
00081 MI_INFO *mi_open(const drizzled::identifier::Table &identifier, int mode, uint32_t open_flags)
00082 {
00083   int lock_error,kfile,open_mode,save_errno,have_rtree=0;
00084   uint32_t i,j,len,errpos,head_length,base_pos,offset,info_length,keys,
00085     key_parts,unique_key_parts,uniques;
00086   char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
00087        data_name[FN_REFLEN], rp_buff[PATH_MAX];
00088   unsigned char *disk_cache= NULL;
00089   unsigned char *disk_pos, *end_pos;
00090   MI_INFO info,*m_info,*old_info;
00091   boost::scoped_ptr<MYISAM_SHARE> share_buff_ap(new MYISAM_SHARE);
00092   MYISAM_SHARE &share_buff= *share_buff_ap.get();
00093   MYISAM_SHARE *share;
00094   boost::scoped_array<ulong> rec_per_key_part_ap(new ulong[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]);
00095   ulong *rec_per_key_part= rec_per_key_part_ap.get();
00096   internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
00097   uint64_t max_key_file_length, max_data_file_length;
00098 
00099   kfile= -1;
00100   lock_error=1;
00101   errpos=0;
00102   head_length=sizeof(share_buff.state.header);
00103   memset(&info, 0, sizeof(info));
00104 
00105   (void)internal::fn_format(org_name,
00106                             identifier.getPath().c_str(), 
00107                             "",
00108                             MI_NAME_IEXT,
00109                             MY_UNPACK_FILENAME);
00110   if (!realpath(org_name,rp_buff))
00111     internal::my_load_path(rp_buff,org_name, NULL);
00112   rp_buff[FN_REFLEN-1]= '\0';
00113   strcpy(name_buff,rp_buff);
00114   THR_LOCK_myisam.lock();
00115   if (!(old_info=test_if_reopen(name_buff)))
00116   {
00117     share= &share_buff;
00118     memset(&share_buff, 0, sizeof(share_buff));
00119     share_buff.state.rec_per_key_part=rec_per_key_part;
00120     share_buff.state.key_root=key_root;
00121     share_buff.state.key_del=key_del;
00122 
00123     if ((kfile=internal::my_open(name_buff,(open_mode=O_RDWR),MYF(0))) < 0)
00124     {
00125       if ((errno != EROFS && errno != EACCES) ||
00126     mode != O_RDONLY ||
00127     (kfile=internal::my_open(name_buff,(open_mode=O_RDONLY),MYF(0))) < 0)
00128   goto err;
00129     }
00130     share->mode=open_mode;
00131     errpos=1;
00132     if (internal::my_read(kfile, share->state.header.file_version, head_length,
00133     MYF(MY_NABP)))
00134     {
00135       errno= HA_ERR_NOT_A_TABLE;
00136       goto err;
00137     }
00138     if (memcmp(share->state.header.file_version, myisam_file_magic, 4))
00139     {
00140       errno=HA_ERR_NOT_A_TABLE;
00141       goto err;
00142     }
00143     share->options= mi_uint2korr(share->state.header.options);
00144     static const uint64_t OLD_FILE_OPTIONS= HA_OPTION_PACK_RECORD |
00145       HA_OPTION_PACK_KEYS |
00146       HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
00147       HA_OPTION_TEMP_COMPRESS_RECORD |
00148       HA_OPTION_TMP_TABLE;
00149     if (share->options & ~OLD_FILE_OPTIONS)
00150     {
00151       errno=HA_ERR_OLD_FILE;
00152       goto err;
00153     }
00154 
00155     /* Don't call realpath() if the name can't be a link */
00156     ssize_t sym_link_size= readlink(org_name,index_name,FN_REFLEN-1);
00157     if (sym_link_size >= 0 )
00158       index_name[sym_link_size]= '\0';
00159     if (!strcmp(name_buff, org_name) || sym_link_size == -1)
00160       (void) strcpy(index_name, org_name);
00161     *strrchr(org_name, '.')= '\0';
00162     (void) internal::fn_format(data_name,org_name,"",MI_NAME_DEXT,
00163                      MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
00164 
00165     info_length=mi_uint2korr(share->state.header.header_length);
00166     base_pos=mi_uint2korr(share->state.header.base_pos);
00167     if (!(disk_cache= (unsigned char*) malloc(info_length+128)))
00168     {
00169       errno=ENOMEM;
00170       goto err;
00171     }
00172     end_pos=disk_cache+info_length;
00173     errpos=2;
00174 
00175     lseek(kfile,0,SEEK_SET);
00176     errpos=3;
00177     if (internal::my_read(kfile,disk_cache,info_length,MYF(MY_NABP)))
00178     {
00179       errno=HA_ERR_CRASHED;
00180       goto err;
00181     }
00182     len=mi_uint2korr(share->state.header.state_info_length);
00183     keys=    (uint) share->state.header.keys;
00184     uniques= (uint) share->state.header.uniques;
00185     key_parts= mi_uint2korr(share->state.header.key_parts);
00186     unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
00187     share->state_diff_length=len-MI_STATE_INFO_SIZE;
00188 
00189     mi_state_info_read(disk_cache, &share->state);
00190     len= mi_uint2korr(share->state.header.base_info_length);
00191     disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
00192     share->state.state_length=base_pos;
00193 
00194     if (share->state.changed & STATE_CRASHED)
00195     {
00196       errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
00197     HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
00198       goto err;
00199     }
00200 
00201     /* sanity check */
00202     if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
00203     {
00204       errno=HA_ERR_CRASHED;
00205       goto err;
00206     }
00207 
00208     if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
00209   key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
00210     {
00211       errno=HA_ERR_UNSUPPORTED;
00212       goto err;
00213     }
00214 
00215     /* Correct max_file_length based on length of sizeof(off_t) */
00216     max_data_file_length=
00217       (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
00218       (((uint64_t) 1 << (share->base.rec_reflength*8))-1) :
00219       (mi_safe_mul(share->base.pack_reclength,
00220        (uint64_t) 1 << (share->base.rec_reflength*8))-1);
00221     max_key_file_length=
00222       mi_safe_mul(MI_MIN_KEY_BLOCK_LENGTH,
00223       ((uint64_t) 1 << (share->base.key_reflength*8))-1);
00224 #if SIZEOF_OFF_T == 4
00225     set_if_smaller(max_data_file_length, INT32_MAX);
00226     set_if_smaller(max_key_file_length, INT32_MAX);
00227 #endif
00228     if (share->base.raid_type)
00229     {
00230       errno=HA_ERR_UNSUPPORTED;
00231       goto err;
00232     }
00233     share->base.max_data_file_length=(internal::my_off_t) max_data_file_length;
00234     share->base.max_key_file_length=(internal::my_off_t) max_key_file_length;
00235 
00236     if (share->options & HA_OPTION_COMPRESS_RECORD)
00237       share->base.max_key_length+=2;  /* For safety */
00238 
00239     /* Add space for node pointer */
00240     share->base.max_key_length+= share->base.key_reflength;
00241 
00242     if (!drizzled::memory::multi_malloc(false,
00243            &share,sizeof(*share),
00244            &share->state.rec_per_key_part,sizeof(long)*key_parts,
00245            &share->keyinfo,keys*sizeof(MI_KEYDEF),
00246            &share->uniqueinfo,uniques*sizeof(MI_UNIQUEDEF),
00247            &share->keyparts,
00248            (key_parts+unique_key_parts+keys+uniques) * sizeof(HA_KEYSEG),
00249            &share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF),
00250            &share->blobs,sizeof(MI_BLOB)*share->base.blobs,
00251            &share->unique_file_name,strlen(name_buff)+1,
00252            &share->index_file_name,strlen(index_name)+1,
00253            &share->data_file_name,strlen(data_name)+1,
00254            &share->state.key_root,keys*sizeof(uint64_t),
00255            &share->state.key_del,
00256            (share->state.header.max_block_size_index*sizeof(uint64_t)),
00257            NULL))
00258       goto err;
00259     errpos=4;
00260     *share=share_buff;
00261     memcpy(share->state.rec_per_key_part, rec_per_key_part,
00262            sizeof(long)*key_parts);
00263     memcpy(share->state.key_root, key_root,
00264            sizeof(internal::my_off_t)*keys);
00265     memcpy(share->state.key_del, key_del,
00266            sizeof(internal::my_off_t) * share->state.header.max_block_size_index);
00267     strcpy(share->unique_file_name, name_buff);
00268     share->unique_name_length= strlen(name_buff);
00269     strcpy(share->index_file_name,  index_name);
00270     strcpy(share->data_file_name,   data_name);
00271 
00272     share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
00273     {
00274       HA_KEYSEG *pos=share->keyparts;
00275       for (i=0 ; i < keys ; i++)
00276       {
00277         share->keyinfo[i].share= share;
00278   disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]);
00279         disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
00280       end_pos);
00281   set_if_smaller(share->blocksize,(uint)share->keyinfo[i].block_length);
00282   share->keyinfo[i].seg=pos;
00283   for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
00284   {
00285     disk_pos=mi_keyseg_read(disk_pos, pos);
00286           if (pos->flag & HA_BLOB_PART &&
00287               ! (share->options & (HA_OPTION_COMPRESS_RECORD |
00288                                    HA_OPTION_PACK_RECORD)))
00289           {
00290             errno= HA_ERR_CRASHED;
00291             goto err;
00292           }
00293     if (pos->type == HA_KEYTYPE_TEXT ||
00294               pos->type == HA_KEYTYPE_VARTEXT1 ||
00295               pos->type == HA_KEYTYPE_VARTEXT2)
00296     {
00297       if (!pos->language)
00298         pos->charset=default_charset_info;
00299       else if (!(pos->charset= get_charset(pos->language)))
00300       {
00301         errno=HA_ERR_UNKNOWN_CHARSET;
00302         goto err;
00303       }
00304     }
00305     else if (pos->type == HA_KEYTYPE_BINARY)
00306       pos->charset= &my_charset_bin;
00307   }
00308         setup_key_functions(share->keyinfo+i);
00309   share->keyinfo[i].end=pos;
00310   pos->type=HA_KEYTYPE_END;     /* End */
00311   pos->length=share->base.rec_reflength;
00312   pos->null_bit=0;
00313   pos->flag=0;          /* For purify */
00314   pos++;
00315       }
00316       for (i=0 ; i < uniques ; i++)
00317       {
00318   disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
00319         disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
00320       HA_KEYSEG_SIZE, end_pos);
00321   share->uniqueinfo[i].seg=pos;
00322   for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
00323   {
00324     disk_pos=mi_keyseg_read(disk_pos, pos);
00325     if (pos->type == HA_KEYTYPE_TEXT ||
00326               pos->type == HA_KEYTYPE_VARTEXT1 ||
00327               pos->type == HA_KEYTYPE_VARTEXT2)
00328     {
00329       if (!pos->language)
00330         pos->charset=default_charset_info;
00331       else if (!(pos->charset= get_charset(pos->language)))
00332       {
00333         errno=HA_ERR_UNKNOWN_CHARSET;
00334         goto err;
00335       }
00336     }
00337   }
00338   share->uniqueinfo[i].end=pos;
00339   pos->type=HA_KEYTYPE_END;     /* End */
00340   pos->null_bit=0;
00341   pos->flag=0;
00342   pos++;
00343       }
00344     }
00345 
00346     disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
00347     for (i=j=offset=0 ; i < share->base.fields ; i++)
00348     {
00349       disk_pos=mi_recinfo_read(disk_pos,&share->rec[i]);
00350       share->rec[i].pack_type=0;
00351       share->rec[i].huff_tree=0;
00352       share->rec[i].offset=offset;
00353       if (share->rec[i].type == (int) FIELD_BLOB)
00354       {
00355   share->blobs[j].pack_length=
00356     share->rec[i].length-portable_sizeof_char_ptr;
00357   share->blobs[j].offset=offset;
00358   j++;
00359       }
00360       offset+=share->rec[i].length;
00361     }
00362     share->rec[i].type=(int) FIELD_LAST;  /* End marker */
00363     if (offset > share->base.reclength)
00364     {
00365       errno= HA_ERR_CRASHED;
00366       goto err;
00367     }
00368 
00369     if (! lock_error)
00370     {
00371       lock_error=1;     /* Database unlocked */
00372     }
00373 
00374     if (mi_open_datafile(&info, share, -1))
00375       goto err;
00376     errpos=5;
00377 
00378     share->kfile=kfile;
00379     share->this_process=(ulong) getpid();
00380     share->last_process= share->state.process;
00381     share->base.key_parts=key_parts;
00382     share->base.all_key_parts=key_parts+unique_key_parts;
00383     if (!(share->last_version=share->state.version))
00384       share->last_version=1;      /* Safety */
00385     share->rec_reflength=share->base.rec_reflength; /* May be changed */
00386     share->base.margin_key_file_length=(share->base.max_key_file_length -
00387           (keys ? MI_INDEX_BLOCK_MARGIN *
00388            share->blocksize * keys : 0));
00389     share->blocksize=min((uint32_t)IO_SIZE,myisam_block_size);
00390     share->data_file_type=STATIC_RECORD;
00391     if (share->options & HA_OPTION_PACK_RECORD)
00392       share->data_file_type = DYNAMIC_RECORD;
00393     free(disk_cache);
00394     disk_cache= NULL;
00395     mi_setup_functions(share);
00396     share->is_log_table= false;
00397     if (myisam_concurrent_insert)
00398     {
00399       share->concurrent_insert=
00400   ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
00401          HA_OPTION_COMPRESS_RECORD |
00402          HA_OPTION_TEMP_COMPRESS_RECORD)) ||
00403    (open_flags & HA_OPEN_TMP_TABLE) || have_rtree) ? 0 : 1;
00404       if (share->concurrent_insert)
00405       {
00406         assert(0);
00407       }
00408     }
00409   }
00410   else
00411   {
00412     share= old_info->s;
00413     if (mode == O_RDWR && share->mode == O_RDONLY)
00414     {
00415       errno=EACCES;       /* Can't open in write mode */
00416       goto err;
00417     }
00418     if (mi_open_datafile(&info, share, old_info->dfile))
00419       goto err;
00420     errpos=5;
00421     have_rtree= old_info->rtree_recursion_state != NULL;
00422   }
00423 
00424   /* alloc and set up private structure parts */
00425   if (!drizzled::memory::multi_malloc(MY_WME,
00426          &m_info,sizeof(MI_INFO),
00427          &info.blobs,sizeof(MI_BLOB)*share->base.blobs,
00428          &info.buff,(share->base.max_key_block_length*2+
00429                      share->base.max_key_length),
00430          &info.lastkey,share->base.max_key_length*3+1,
00431          &info.first_mbr_key, share->base.max_key_length,
00432          &info.filename, identifier.getPath().length()+1,
00433          &info.rtree_recursion_state,have_rtree ? 1024 : 0,
00434          NULL))
00435     goto err;
00436   errpos=6;
00437 
00438   if (!have_rtree)
00439     info.rtree_recursion_state= NULL;
00440 
00441   strcpy(info.filename, identifier.getPath().c_str());
00442   memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs);
00443   info.lastkey2=info.lastkey+share->base.max_key_length;
00444 
00445   info.s=share;
00446   info.lastpos= HA_OFFSET_ERROR;
00447   info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
00448   info.opt_flag=READ_CHECK_USED;
00449   info.this_unique= (ulong) info.dfile; /* Uniq number in process */
00450   if (share->data_file_type == COMPRESSED_RECORD)
00451     info.this_unique= share->state.unique;
00452   info.this_loop=0;       /* Update counter */
00453   info.last_unique= share->state.unique;
00454   info.last_loop=   share->state.update_count;
00455   if (mode == O_RDONLY)
00456     share->options|=HA_OPTION_READ_ONLY_DATA;
00457   info.lock_type=F_UNLCK;
00458   info.quick_mode=0;
00459   info.bulk_insert=0;
00460   info.errkey= -1;
00461   info.page_changed=1;
00462   info.read_record=share->read_record;
00463   share->reopen++;
00464   share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
00465   if (share->options & HA_OPTION_READ_ONLY_DATA)
00466   {
00467     info.lock_type=F_RDLCK;
00468     share->r_locks++;
00469     share->tot_locks++;
00470   }
00471   if ((open_flags & HA_OPEN_TMP_TABLE) ||
00472       (share->options & HA_OPTION_TMP_TABLE))
00473   {
00474     share->temporary=share->delay_key_write=1;
00475     share->write_flag=MYF(MY_NABP);
00476     /*
00477      * The following two statements are commented out as a fix of
00478      * bug https://bugs.launchpad.net/drizzle/+bug/387627
00479      *
00480      * UPDATE can be TRUNCATE on TEMPORARY TABLE (MyISAM).
00481      * The root cause of why this makes a difference hasn't
00482      * been found, but this fixes things for now.
00483      */
00484 //    share->w_locks++;     // We don't have to update status
00485 //    share->tot_locks++;
00486     info.lock_type=F_WRLCK;
00487   }
00488 
00489   share->delay_key_write= 1;
00490   info.state= &share->state.state;  /* Change global values by default */
00491 
00492   /* Allocate buffer for one record */
00493 
00494   /* prerequisites: memset(info, 0) && info->s=share; are met. */
00495   if (!mi_alloc_rec_buff(&info, SIZE_MAX, &info.rec_buff))
00496     goto err;
00497   memset(info.rec_buff, 0, mi_get_rec_buff_len(&info, info.rec_buff));
00498 
00499   *m_info=info;
00500   myisam_open_list.push_front(m_info);
00501 
00502   THR_LOCK_myisam.unlock();
00503   return(m_info);
00504 
00505 err:
00506   free(disk_cache);
00507   save_errno=errno ? errno : HA_ERR_END_OF_FILE;
00508   if ((save_errno == HA_ERR_CRASHED) ||
00509       (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
00510       (save_errno == HA_ERR_CRASHED_ON_REPAIR))
00511     mi_report_error(save_errno, identifier.getPath().c_str());
00512   switch (errpos) {
00513   case 6:
00514     free((unsigned char*) m_info);
00515     /* fall through */
00516   case 5:
00517     internal::my_close(info.dfile,MYF(0));
00518     if (old_info)
00519       break;          /* Don't remove open table */
00520     /* fall through */
00521   case 4:
00522     free((unsigned char*) share);
00523     /* fall through */
00524   case 3:
00525     /* fall through */
00526   case 1:
00527     internal::my_close(kfile,MYF(0));
00528     /* fall through */
00529   case 0:
00530   default:
00531     break;
00532   }
00533   THR_LOCK_myisam.unlock();
00534   errno=save_errno;
00535   return (NULL);
00536 } /* mi_open */
00537 
00538 
00539 unsigned char *mi_alloc_rec_buff(MI_INFO *info, size_t length, unsigned char **buf)
00540 {
00541   uint32_t extra;
00542   uint32_t old_length= 0;
00543 
00544   if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
00545   {
00546     unsigned char *newptr = *buf;
00547 
00548     /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
00549     if (length == SIZE_MAX)
00550     {
00551       if (info->s->options & HA_OPTION_COMPRESS_RECORD)
00552         length= max(info->s->base.pack_reclength, info->s->max_pack_length);
00553       else
00554         length= info->s->base.pack_reclength;
00555       length= max((uint32_t)length, info->s->base.max_key_length);
00556       /* Avoid unnecessary realloc */
00557       if (newptr && length == old_length)
00558   return newptr;
00559     }
00560 
00561     extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
00562       ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
00563       MI_REC_BUFF_OFFSET : 0);
00564     if (extra && newptr)
00565       newptr-= MI_REC_BUFF_OFFSET;
00566     void *tmpnewptr= NULL;
00567     if (!(tmpnewptr= realloc(newptr, length+extra+8))) 
00568       return newptr;
00569     newptr= (unsigned char *)tmpnewptr;
00570     *((uint32_t *) newptr)= (uint32_t) length;
00571     *buf= newptr+(extra ?  MI_REC_BUFF_OFFSET : 0);
00572   }
00573   return *buf;
00574 }
00575 
00576 
00577 static uint64_t mi_safe_mul(uint64_t a, uint64_t b)
00578 {
00579   uint64_t max_val= ~ (uint64_t) 0;   /* internal::my_off_t is unsigned */
00580 
00581   if (!a || max_val / a < b)
00582     return max_val;
00583   return a*b;
00584 }
00585 
00586   /* Set up functions in structs */
00587 
00588 void mi_setup_functions(register MYISAM_SHARE *share)
00589 {
00590   if (share->options & HA_OPTION_PACK_RECORD)
00591   {
00592     share->read_record=_mi_read_dynamic_record;
00593     share->read_rnd=_mi_read_rnd_dynamic_record;
00594     share->delete_record=_mi_delete_dynamic_record;
00595     share->compare_record=_mi_cmp_dynamic_record;
00596     share->compare_unique=_mi_cmp_dynamic_unique;
00597     share->calc_checksum= mi_checksum;
00598 
00599     /* add bits used to pack data to pack_reclength for faster allocation */
00600     share->base.pack_reclength+= share->base.pack_bits;
00601     if (share->base.blobs)
00602     {
00603       share->update_record=_mi_update_blob_record;
00604       share->write_record=_mi_write_blob_record;
00605     }
00606     else
00607     {
00608       share->write_record=_mi_write_dynamic_record;
00609       share->update_record=_mi_update_dynamic_record;
00610     }
00611   }
00612   else
00613   {
00614     share->read_record=_mi_read_static_record;
00615     share->read_rnd=_mi_read_rnd_static_record;
00616     share->delete_record=_mi_delete_static_record;
00617     share->compare_record=_mi_cmp_static_record;
00618     share->update_record=_mi_update_static_record;
00619     share->write_record=_mi_write_static_record;
00620     share->compare_unique=_mi_cmp_static_unique;
00621     share->calc_checksum= mi_static_checksum;
00622   }
00623   share->file_read= mi_nommap_pread;
00624   share->file_write= mi_nommap_pwrite;
00625   share->calc_checksum=0;
00626 }
00627 
00628 
00629 static void setup_key_functions(register MI_KEYDEF *keyinfo)
00630 {
00631   {
00632     keyinfo->ck_insert = _mi_ck_write;
00633     keyinfo->ck_delete = _mi_ck_delete;
00634   }
00635   if (keyinfo->flag & HA_BINARY_PACK_KEY)
00636   {           /* Simple prefix compression */
00637     keyinfo->bin_search=_mi_seq_search;
00638     keyinfo->get_key=_mi_get_binary_pack_key;
00639     keyinfo->pack_key=_mi_calc_bin_pack_key_length;
00640     keyinfo->store_key=_mi_store_bin_pack_key;
00641   }
00642   else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
00643   {
00644     keyinfo->get_key= _mi_get_pack_key;
00645     if (keyinfo->seg[0].flag & HA_PACK_KEY)
00646     {           /* Prefix compression */
00647       /*
00648         _mi_prefix_search() compares end-space against ASCII blank (' ').
00649         It cannot be used for character sets, that do not encode the
00650         blank character like ASCII does. UCS2 is an example. All
00651         character sets with a fixed width > 1 or a mimimum width > 1
00652         cannot represent blank like ASCII does. In these cases we have
00653         to use _mi_seq_search() for the search.
00654       */
00655       if (not keyinfo->seg->charset || keyinfo->seg->charset->use_strnxfrm() ||
00656           (keyinfo->seg->flag & HA_NULL_PART) ||
00657           (keyinfo->seg->charset->mbminlen > 1))
00658         keyinfo->bin_search=_mi_seq_search;
00659       else
00660         keyinfo->bin_search=_mi_prefix_search;
00661       keyinfo->pack_key=_mi_calc_var_pack_key_length;
00662       keyinfo->store_key=_mi_store_var_pack_key;
00663     }
00664     else
00665     {
00666       keyinfo->bin_search=_mi_seq_search;
00667       keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
00668       keyinfo->store_key=_mi_store_static_key;
00669     }
00670   }
00671   else
00672   {
00673     keyinfo->bin_search=_mi_bin_search;
00674     keyinfo->get_key=_mi_get_static_key;
00675     keyinfo->pack_key=_mi_calc_static_key_length;
00676     keyinfo->store_key=_mi_store_static_key;
00677   }
00678   return;
00679 }
00680 
00681 
00682 /*
00683    Function to save and store the header in the index file (.MYI)
00684 */
00685 
00686 uint32_t mi_state_info_write(int file, MI_STATE_INFO *state, uint32_t pWrite)
00687 {
00688   unsigned char  buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
00689   unsigned char *ptr=buff;
00690   uint  i, keys= (uint) state->header.keys,
00691   key_blocks=state->header.max_block_size_index;
00692 
00693   memcpy(ptr,&state->header,sizeof(state->header));
00694   ptr+=sizeof(state->header);
00695 
00696   /* open_count must be first because of _mi_mark_file_changed ! */
00697   mi_int2store(ptr,state->open_count);    ptr +=2;
00698   *ptr++= (unsigned char)state->changed; *ptr++= state->sortkey;
00699   mi_rowstore(ptr,state->state.records);  ptr +=8;
00700   mi_rowstore(ptr,state->state.del);    ptr +=8;
00701   mi_rowstore(ptr,state->split);    ptr +=8;
00702   mi_sizestore(ptr,state->dellink);   ptr +=8;
00703   mi_sizestore(ptr,state->state.key_file_length); ptr +=8;
00704   mi_sizestore(ptr,state->state.data_file_length);  ptr +=8;
00705   mi_sizestore(ptr,state->state.empty);   ptr +=8;
00706   mi_sizestore(ptr,state->state.key_empty); ptr +=8;
00707   mi_int8store(ptr,state->auto_increment);  ptr +=8;
00708   mi_int8store(ptr,(uint64_t) state->state.checksum);ptr +=8;
00709   mi_int4store(ptr,state->process);   ptr +=4;
00710   mi_int4store(ptr,state->unique);    ptr +=4;
00711   mi_int4store(ptr,state->status);    ptr +=4;
00712   mi_int4store(ptr,state->update_count);  ptr +=4;
00713 
00714   ptr+=state->state_diff_length;
00715 
00716   for (i=0; i < keys; i++)
00717   {
00718     mi_sizestore(ptr,state->key_root[i]); ptr +=8;
00719   }
00720   for (i=0; i < key_blocks; i++)
00721   {
00722     mi_sizestore(ptr,state->key_del[i]);  ptr +=8;
00723   }
00724   if (pWrite & 2)       /* From isamchk */
00725   {
00726     uint32_t key_parts= mi_uint2korr(state->header.key_parts);
00727     mi_int4store(ptr,state->sec_index_changed); ptr +=4;
00728     mi_int4store(ptr,state->sec_index_used);  ptr +=4;
00729     mi_int4store(ptr,state->version);   ptr +=4;
00730     mi_int8store(ptr,state->key_map);   ptr +=8;
00731     mi_int8store(ptr,(uint64_t) state->create_time);  ptr +=8;
00732     mi_int8store(ptr,(uint64_t) state->recover_time); ptr +=8;
00733     mi_int8store(ptr,(uint64_t) state->check_time); ptr +=8;
00734     mi_sizestore(ptr,state->rec_per_key_rows);  ptr+=8;
00735     for (i=0 ; i < key_parts ; i++)
00736     {
00737       mi_int4store(ptr,state->rec_per_key_part[i]);  ptr+=4;
00738     }
00739   }
00740 
00741   if (pWrite & 1)
00742     return(my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
00743         MYF(MY_NABP | MY_THREADSAFE)) != 0);
00744   return(internal::my_write(file, buff, (size_t) (ptr-buff),
00745            MYF(MY_NABP)) != 0);
00746 }
00747 
00748 
00749 static unsigned char *mi_state_info_read(unsigned char *ptr, MI_STATE_INFO *state)
00750 {
00751   uint32_t i,keys,key_parts,key_blocks;
00752   memcpy(&state->header,ptr, sizeof(state->header));
00753   ptr +=sizeof(state->header);
00754   keys=(uint) state->header.keys;
00755   key_parts=mi_uint2korr(state->header.key_parts);
00756   key_blocks=state->header.max_block_size_index;
00757 
00758   state->open_count = mi_uint2korr(ptr);  ptr +=2;
00759   state->changed= *ptr++;
00760   state->sortkey = (uint) *ptr++;
00761   state->state.records= mi_rowkorr(ptr);  ptr +=8;
00762   state->state.del = mi_rowkorr(ptr);   ptr +=8;
00763   state->split  = mi_rowkorr(ptr);    ptr +=8;
00764   state->dellink= mi_sizekorr(ptr);   ptr +=8;
00765   state->state.key_file_length = mi_sizekorr(ptr);  ptr +=8;
00766   state->state.data_file_length= mi_sizekorr(ptr);  ptr +=8;
00767   state->state.empty  = mi_sizekorr(ptr); ptr +=8;
00768   state->state.key_empty= mi_sizekorr(ptr); ptr +=8;
00769   state->auto_increment=mi_uint8korr(ptr);  ptr +=8;
00770   state->state.checksum=(ha_checksum) mi_uint8korr(ptr);  ptr +=8;
00771   state->process= mi_uint4korr(ptr);    ptr +=4;
00772   state->unique = mi_uint4korr(ptr);    ptr +=4;
00773   state->status = mi_uint4korr(ptr);    ptr +=4;
00774   state->update_count=mi_uint4korr(ptr);  ptr +=4;
00775 
00776   ptr+= state->state_diff_length;
00777 
00778   for (i=0; i < keys; i++)
00779   {
00780     state->key_root[i]= mi_sizekorr(ptr); ptr +=8;
00781   }
00782   for (i=0; i < key_blocks; i++)
00783   {
00784     state->key_del[i] = mi_sizekorr(ptr); ptr +=8;
00785   }
00786   state->sec_index_changed = mi_uint4korr(ptr); ptr +=4;
00787   state->sec_index_used =    mi_uint4korr(ptr); ptr +=4;
00788   state->version     = mi_uint4korr(ptr); ptr +=4;
00789   state->key_map     = mi_uint8korr(ptr); ptr +=8;
00790   state->create_time = (time_t) mi_sizekorr(ptr); ptr +=8;
00791   state->recover_time =(time_t) mi_sizekorr(ptr); ptr +=8;
00792   state->check_time =  (time_t) mi_sizekorr(ptr); ptr +=8;
00793   state->rec_per_key_rows=mi_sizekorr(ptr); ptr +=8;
00794   for (i=0 ; i < key_parts ; i++)
00795   {
00796     state->rec_per_key_part[i]= mi_uint4korr(ptr); ptr+=4;
00797   }
00798   return ptr;
00799 }
00800 
00801 
00802 uint32_t mi_state_info_read_dsk(int file, MI_STATE_INFO *state, bool pRead)
00803 {
00804   unsigned char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE];
00805 
00806   if (pRead)
00807   {
00808     if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP)))
00809       return 1;
00810   }
00811   else if (internal::my_read(file, buff, state->state_length,MYF(MY_NABP)))
00812     return 1;
00813   mi_state_info_read(buff, state);
00814 
00815   return 0;
00816 }
00817 
00818 
00819 /****************************************************************************
00820 **  store and read of MI_BASE_INFO
00821 ****************************************************************************/
00822 
00823 uint32_t mi_base_info_write(int file, MI_BASE_INFO *base)
00824 {
00825   unsigned char buff[MI_BASE_INFO_SIZE], *ptr=buff;
00826 
00827   mi_sizestore(ptr,base->keystart);     ptr +=8;
00828   mi_sizestore(ptr,base->max_data_file_length);   ptr +=8;
00829   mi_sizestore(ptr,base->max_key_file_length);    ptr +=8;
00830   mi_rowstore(ptr,base->records);     ptr +=8;
00831   mi_rowstore(ptr,base->reloc);       ptr +=8;
00832   mi_int4store(ptr,base->mean_row_length);    ptr +=4;
00833   mi_int4store(ptr,base->reclength);      ptr +=4;
00834   mi_int4store(ptr,base->pack_reclength);   ptr +=4;
00835   mi_int4store(ptr,base->min_pack_length);    ptr +=4;
00836   mi_int4store(ptr,base->max_pack_length);    ptr +=4;
00837   mi_int4store(ptr,base->min_block_length);   ptr +=4;
00838   mi_int4store(ptr,base->fields);     ptr +=4;
00839   mi_int4store(ptr,base->pack_fields);      ptr +=4;
00840   *ptr++=base->rec_reflength;
00841   *ptr++=base->key_reflength;
00842   *ptr++=base->keys;
00843   *ptr++=base->auto_key;
00844   mi_int2store(ptr,base->pack_bits);      ptr +=2;
00845   mi_int2store(ptr,base->blobs);      ptr +=2;
00846   mi_int2store(ptr,base->max_key_block_length);   ptr +=2;
00847   mi_int2store(ptr,base->max_key_length);   ptr +=2;
00848   mi_int2store(ptr,base->extra_alloc_bytes);    ptr +=2;
00849   *ptr++= base->extra_alloc_procent;
00850   /* old raid info  slots */
00851   *ptr++= 0;
00852   mi_int2store(ptr,UINT16_C(0));      ptr +=2;
00853   mi_int4store(ptr,UINT32_C(0));            ptr +=4;
00854 
00855   memset(ptr, 0, 6);          ptr +=6; /* extra */
00856   return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
00857 }
00858 
00859 
00860 static unsigned char *my_n_base_info_read(unsigned char *ptr, MI_BASE_INFO *base)
00861 {
00862   base->keystart = mi_sizekorr(ptr);      ptr +=8;
00863   base->max_data_file_length = mi_sizekorr(ptr);  ptr +=8;
00864   base->max_key_file_length = mi_sizekorr(ptr);   ptr +=8;
00865   base->records =  (ha_rows) mi_sizekorr(ptr);    ptr +=8;
00866   base->reloc = (ha_rows) mi_sizekorr(ptr);   ptr +=8;
00867   base->mean_row_length = mi_uint4korr(ptr);    ptr +=4;
00868   base->reclength = mi_uint4korr(ptr);      ptr +=4;
00869   base->pack_reclength = mi_uint4korr(ptr);   ptr +=4;
00870   base->min_pack_length = mi_uint4korr(ptr);    ptr +=4;
00871   base->max_pack_length = mi_uint4korr(ptr);    ptr +=4;
00872   base->min_block_length = mi_uint4korr(ptr);   ptr +=4;
00873   base->fields = mi_uint4korr(ptr);     ptr +=4;
00874   base->pack_fields = mi_uint4korr(ptr);    ptr +=4;
00875 
00876   base->rec_reflength = *ptr++;
00877   base->key_reflength = *ptr++;
00878   base->keys=   *ptr++;
00879   base->auto_key= *ptr++;
00880   base->pack_bits = mi_uint2korr(ptr);      ptr +=2;
00881   base->blobs = mi_uint2korr(ptr);      ptr +=2;
00882   base->max_key_block_length= mi_uint2korr(ptr);  ptr +=2;
00883   base->max_key_length = mi_uint2korr(ptr);   ptr +=2;
00884   base->extra_alloc_bytes = mi_uint2korr(ptr);    ptr +=2;
00885   base->extra_alloc_procent = *ptr++;
00886 
00887   /* advance past raid_type (1) raid_chunks (2) and raid_chunksize (4) */
00888   ptr+= 7;
00889 
00890   ptr+=6;
00891   return ptr;
00892 }
00893 
00894 /*--------------------------------------------------------------------------
00895   mi_keydef
00896 ---------------------------------------------------------------------------*/
00897 
00898 uint32_t mi_keydef_write(int file, MI_KEYDEF *keydef)
00899 {
00900   unsigned char buff[MI_KEYDEF_SIZE];
00901   unsigned char *ptr=buff;
00902 
00903   *ptr++ = (unsigned char) keydef->keysegs;
00904   *ptr++ = keydef->key_alg;     /* Rtree or Btree */
00905   mi_int2store(ptr,keydef->flag);   ptr +=2;
00906   mi_int2store(ptr,keydef->block_length); ptr +=2;
00907   mi_int2store(ptr,keydef->keylength);    ptr +=2;
00908   mi_int2store(ptr,keydef->minlength);    ptr +=2;
00909   mi_int2store(ptr,keydef->maxlength);    ptr +=2;
00910   return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
00911 }
00912 
00913 static unsigned char *mi_keydef_read(unsigned char *ptr, MI_KEYDEF *keydef)
00914 {
00915    keydef->keysegs  = (uint) *ptr++;
00916    keydef->key_alg  = *ptr++;   /* Rtree or Btree */
00917 
00918    keydef->flag   = mi_uint2korr(ptr);  ptr +=2;
00919    keydef->block_length = mi_uint2korr(ptr);  ptr +=2;
00920    keydef->keylength  = mi_uint2korr(ptr);  ptr +=2;
00921    keydef->minlength  = mi_uint2korr(ptr);  ptr +=2;
00922    keydef->maxlength  = mi_uint2korr(ptr);  ptr +=2;
00923    keydef->block_size_index= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
00924    keydef->underflow_block_length=keydef->block_length/3;
00925    keydef->version  = 0;      /* Not saved */
00926    return ptr;
00927 }
00928 
00929 /***************************************************************************
00930 **  mi_keyseg
00931 ***************************************************************************/
00932 
00933 int mi_keyseg_write(int file, const HA_KEYSEG *keyseg)
00934 {
00935   unsigned char buff[HA_KEYSEG_SIZE];
00936   unsigned char *ptr=buff;
00937   ulong pos;
00938 
00939   *ptr++= keyseg->type;
00940   *ptr++= keyseg->language;
00941   *ptr++= keyseg->null_bit;
00942   *ptr++= keyseg->bit_start;
00943   *ptr++= keyseg->bit_end;
00944   *ptr++= keyseg->bit_length;
00945   mi_int2store(ptr,keyseg->flag); ptr+=2;
00946   mi_int2store(ptr,keyseg->length); ptr+=2;
00947   mi_int4store(ptr,keyseg->start);  ptr+=4;
00948   pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
00949   mi_int4store(ptr, pos);
00950   ptr+=4;
00951 
00952   return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
00953 }
00954 
00955 
00956 static unsigned char *mi_keyseg_read(unsigned char *ptr, HA_KEYSEG *keyseg)
00957 {
00958    keyseg->type   = *ptr++;
00959    keyseg->language = *ptr++;
00960    keyseg->null_bit = *ptr++;
00961    keyseg->bit_start  = *ptr++;
00962    keyseg->bit_end  = *ptr++;
00963    keyseg->bit_length   = *ptr++;
00964    keyseg->flag   = mi_uint2korr(ptr);  ptr +=2;
00965    keyseg->length = mi_uint2korr(ptr);  ptr +=2;
00966    keyseg->start  = mi_uint4korr(ptr);  ptr +=4;
00967    keyseg->null_pos = mi_uint4korr(ptr);  ptr +=4;
00968    keyseg->charset=0;       /* Will be filled in later */
00969    if (keyseg->null_bit)
00970      keyseg->bit_pos= (uint16_t)(keyseg->null_pos + (keyseg->null_bit == 7));
00971    else
00972    {
00973      keyseg->bit_pos= (uint16_t)keyseg->null_pos;
00974      keyseg->null_pos= 0;
00975    }
00976    return ptr;
00977 }
00978 
00979 /*--------------------------------------------------------------------------
00980   mi_uniquedef
00981 ---------------------------------------------------------------------------*/
00982 
00983 uint32_t mi_uniquedef_write(int file, MI_UNIQUEDEF *def)
00984 {
00985   unsigned char buff[MI_UNIQUEDEF_SIZE];
00986   unsigned char *ptr=buff;
00987 
00988   mi_int2store(ptr,def->keysegs);   ptr+=2;
00989   *ptr++=  (unsigned char) def->key;
00990   *ptr++ = (unsigned char) def->null_are_equal;
00991 
00992   return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
00993 }
00994 
00995 static unsigned char *mi_uniquedef_read(unsigned char *ptr, MI_UNIQUEDEF *def)
00996 {
00997    def->keysegs = mi_uint2korr(ptr);
00998    def->key = ptr[2];
00999    def->null_are_equal=ptr[3];
01000    return ptr+4;        /* 1 extra byte */
01001 }
01002 
01003 /***************************************************************************
01004 **  MI_COLUMNDEF
01005 ***************************************************************************/
01006 
01007 uint32_t mi_recinfo_write(int file, MI_COLUMNDEF *recinfo)
01008 {
01009   unsigned char buff[MI_COLUMNDEF_SIZE];
01010   unsigned char *ptr=buff;
01011 
01012   mi_int2store(ptr,recinfo->type);  ptr +=2;
01013   mi_int2store(ptr,recinfo->length);  ptr +=2;
01014   *ptr++ = recinfo->null_bit;
01015   mi_int2store(ptr,recinfo->null_pos);  ptr+= 2;
01016   return internal::my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
01017 }
01018 
01019 static unsigned char *mi_recinfo_read(unsigned char *ptr, MI_COLUMNDEF *recinfo)
01020 {
01021    recinfo->type=  mi_sint2korr(ptr); ptr +=2;
01022    recinfo->length=mi_uint2korr(ptr); ptr +=2;
01023    recinfo->null_bit= (uint8_t) *ptr++;
01024    recinfo->null_pos=mi_uint2korr(ptr); ptr +=2;
01025    return ptr;
01026 }
01027 
01028 /**************************************************************************
01029 Open data file
01030 We can't use dup() here as the data file descriptors need to have different
01031 active seek-positions.
01032 
01033 The argument file_to_dup is here for the future if there would on some OS
01034 exist a dup()-like call that would give us two different file descriptors.
01035 *************************************************************************/
01036 
01037 int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, int file_to_dup)
01038 {
01039   (void)file_to_dup; 
01040   info->dfile=internal::my_open(share->data_file_name, share->mode,
01041                       MYF(MY_WME));
01042   return info->dfile >= 0 ? 0 : 1;
01043 }
01044 
01045 
01046 int mi_open_keyfile(MYISAM_SHARE *share)
01047 {
01048   if ((share->kfile=internal::my_open(share->unique_file_name, share->mode,
01049                             MYF(MY_WME))) < 0)
01050     return 1;
01051   return 0;
01052 }
01053 
01054 
01055 /*
01056   Disable all indexes.
01057 
01058   SYNOPSIS
01059     mi_disable_indexes()
01060     info        A pointer to the MyISAM storage engine MI_INFO struct.
01061 
01062   DESCRIPTION
01063     Disable all indexes.
01064 
01065   RETURN
01066     0  ok
01067 */
01068 
01069 int mi_disable_indexes(MI_INFO *info)
01070 {
01071   MYISAM_SHARE *share= info->s;
01072 
01073   mi_clear_all_keys_active(share->state.key_map);
01074   return 0;
01075 }
01076 
01077 
01078 /*
01079   Enable all indexes
01080 
01081   SYNOPSIS
01082     mi_enable_indexes()
01083     info        A pointer to the MyISAM storage engine MI_INFO struct.
01084 
01085   DESCRIPTION
01086     Enable all indexes. The indexes might have been disabled
01087     by mi_disable_index() before.
01088     The function works only if both data and indexes are empty,
01089     otherwise a repair is required.
01090     To be sure, call handler::delete_all_rows() before.
01091 
01092   RETURN
01093     0  ok
01094     HA_ERR_CRASHED data or index is non-empty.
01095 */
01096 
01097 int mi_enable_indexes(MI_INFO *info)
01098 {
01099   int error= 0;
01100   MYISAM_SHARE *share= info->s;
01101 
01102   if (share->state.state.data_file_length ||
01103       (share->state.state.key_file_length != share->base.keystart))
01104   {
01105     mi_print_error(info->s, HA_ERR_CRASHED);
01106     error= HA_ERR_CRASHED;
01107   }
01108   else
01109     mi_set_all_keys_active(share->state.key_map, share->base.keys);
01110   return error;
01111 }
01112 
01113 
01114 /*
01115   Test if indexes are disabled.
01116 
01117   SYNOPSIS
01118     mi_indexes_are_disabled()
01119     info        A pointer to the MyISAM storage engine MI_INFO struct.
01120 
01121   DESCRIPTION
01122     Test if indexes are disabled.
01123 
01124   RETURN
01125     0  indexes are not disabled
01126     1  all indexes are disabled
01127     2  non-unique indexes are disabled
01128 */
01129 
01130 int mi_indexes_are_disabled(MI_INFO *info)
01131 {
01132   MYISAM_SHARE *share= info->s;
01133 
01134   /*
01135     No keys or all are enabled. keys is the number of keys. Left shifted
01136     gives us only one bit set. When decreased by one, gives us all all bits
01137     up to this one set and it gets unset.
01138   */
01139   if (!share->base.keys ||
01140       (mi_is_all_keys_active(share->state.key_map, share->base.keys)))
01141     return 0;
01142 
01143   /* All are disabled */
01144   if (mi_is_any_key_active(share->state.key_map))
01145     return 1;
01146 
01147   /*
01148     We have keys. Some enabled, some disabled.
01149     Don't check for any non-unique disabled but return directly 2
01150   */
01151   return 2;
01152 }
01153