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