Drizzled Public API Documentation

mi_create.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 /* Create a MyISAM table */
00017 
00018 #include "myisam_priv.h"
00019 #include <drizzled/internal/my_bit.h>
00020 #include <drizzled/internal/my_sys.h>
00021 
00022 #include <drizzled/util/test.h>
00023 #include <drizzled/global_charset_info.h>
00024 #include <drizzled/error.h>
00025 
00026 #include <cassert>
00027 #include <algorithm>
00028 
00029 using namespace std;
00030 using namespace drizzled;
00031 
00032 /*
00033   Old options is used when recreating database, from myisamchk
00034 */
00035 
00036 int mi_create(const char *name,uint32_t keys,MI_KEYDEF *keydefs,
00037         uint32_t columns, MI_COLUMNDEF *recinfo,
00038         uint32_t uniques, MI_UNIQUEDEF *uniquedefs,
00039         MI_CREATE_INFO *ci,uint32_t flags)
00040 {
00041   register uint32_t i, j;
00042   int dfile= 0, file= 0;
00043   int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
00044   myf create_flag;
00045   uint32_t fields,length,max_key_length,packed,pointer,real_length_diff,
00046        key_length,info_length,key_segs,options,min_key_length_skip,
00047        base_pos,long_varchar_count,varchar_length,
00048        max_key_block_length,unique_key_parts,fulltext_keys,offset;
00049   uint32_t aligned_key_start, block_length;
00050   ulong reclength, real_reclength,min_pack_length;
00051   char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
00052   ulong pack_reclength;
00053   uint64_t tot_length,max_rows, tmp;
00054   enum en_fieldtype type;
00055   MYISAM_SHARE share;
00056   MI_KEYDEF *keydef,tmp_keydef;
00057   MI_UNIQUEDEF *uniquedef;
00058   HA_KEYSEG *keyseg,tmp_keyseg;
00059   MI_COLUMNDEF *rec;
00060   ulong *rec_per_key_part;
00061   internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
00062   MI_CREATE_INFO tmp_create_info;
00063 
00064   if (!ci)
00065   {
00066     memset(&tmp_create_info, 0, sizeof(tmp_create_info));
00067     ci=&tmp_create_info;
00068   }
00069 
00070   if (keys + uniques > MI_MAX_KEY || columns == 0)
00071   {
00072     return(errno=HA_WRONG_CREATE_OPTION);
00073   }
00074   errpos= 0;
00075   options= 0;
00076   memset(&share, 0, sizeof(share));
00077 
00078   if (flags & HA_DONT_TOUCH_DATA)
00079   {
00080     if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
00081       options=ci->old_options &
00082   (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
00083    HA_OPTION_READ_ONLY_DATA |
00084    HA_OPTION_TMP_TABLE );
00085     else
00086       options=ci->old_options &
00087   (HA_OPTION_TMP_TABLE );
00088   }
00089 
00090   if (ci->reloc_rows > ci->max_rows)
00091     ci->reloc_rows=ci->max_rows;    /* Check if wrong parameter */
00092 
00093   if (!(rec_per_key_part=
00094   (ulong*) malloc((keys + uniques)*MI_MAX_KEY_SEG*sizeof(long))))
00095     return(errno);
00096   memset(rec_per_key_part, 0, (keys + uniques)*MI_MAX_KEY_SEG*sizeof(long));
00097 
00098   /* Start by checking fields and field-types used */
00099 
00100   reclength=varchar_length=long_varchar_count=packed=
00101     min_pack_length=pack_reclength=0;
00102   for (rec=recinfo, fields=0 ;
00103        fields != columns ;
00104        rec++,fields++)
00105   {
00106     reclength+=rec->length;
00107     if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
00108   type != FIELD_CHECK)
00109     {
00110       packed++;
00111       if (type == FIELD_BLOB)
00112       {
00113   share.base.blobs++;
00114   if (pack_reclength != INT32_MAX)
00115   {
00116     if (rec->length == 4+portable_sizeof_char_ptr)
00117       pack_reclength= INT32_MAX;
00118     else
00119       pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */
00120   }
00121       }
00122       else if (type == FIELD_SKIP_PRESPACE ||
00123          type == FIELD_SKIP_ENDSPACE)
00124       {
00125   if (pack_reclength != INT32_MAX)
00126     pack_reclength+= rec->length > 255 ? 2 : 1;
00127   min_pack_length++;
00128       }
00129       else if (type == FIELD_VARCHAR)
00130       {
00131   varchar_length+= rec->length-1;          /* Used for min_pack_length */
00132   packed--;
00133   pack_reclength++;
00134         min_pack_length++;
00135         /* We must test for 257 as length includes pack-length */
00136         if (test(rec->length >= 257))
00137   {
00138     long_varchar_count++;
00139     pack_reclength+= 2;     /* May be packed on 3 bytes */
00140   }
00141       }
00142       else if (type != FIELD_SKIP_ZERO)
00143       {
00144   min_pack_length+=rec->length;
00145   packed--;       /* Not a pack record type */
00146       }
00147     }
00148     else          /* FIELD_NORMAL */
00149       min_pack_length+=rec->length;
00150   }
00151   if ((packed & 7) == 1)
00152   {       /* Bad packing, try to remove a zero-field */
00153     while (rec != recinfo)
00154     {
00155       rec--;
00156       if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
00157       {
00158         /*
00159           NOTE1: here we change a field type FIELD_SKIP_ZERO ->
00160           FIELD_NORMAL
00161         */
00162   rec->type=(int) FIELD_NORMAL;
00163   packed--;
00164   min_pack_length++;
00165   break;
00166       }
00167     }
00168   }
00169 
00170   if (packed || (flags & HA_PACK_RECORD))
00171     options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
00172   if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
00173     min_pack_length+= varchar_length;
00174   if (flags & HA_CREATE_TMP_TABLE)
00175   {
00176     options|= HA_OPTION_TMP_TABLE;
00177     create_mode|= O_EXCL;
00178   }
00179 
00180   packed=(packed+7)/8;
00181   if (pack_reclength != INT32_MAX)
00182     pack_reclength+= reclength+packed +
00183       test(test_all_bits(options,
00184                          uint32_t(HA_PACK_RECORD)));
00185   min_pack_length+=packed;
00186 
00187   if (!ci->data_file_length && ci->max_rows)
00188   {
00189     if (pack_reclength == INT32_MAX ||
00190              (~(uint64_t) 0)/ci->max_rows < (uint64_t) pack_reclength)
00191       ci->data_file_length= ~(uint64_t) 0;
00192     else
00193       ci->data_file_length=(uint64_t) ci->max_rows*pack_reclength;
00194   }
00195   else if (!ci->max_rows)
00196     ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
00197            ((options & HA_OPTION_PACK_RECORD) ?
00198             3 : 0)));
00199 
00200   if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
00201     pointer=mi_get_pointer_length(ci->data_file_length, data_pointer_size);
00202   else
00203     pointer=mi_get_pointer_length(ci->max_rows, data_pointer_size);
00204   if (!(max_rows=(uint64_t) ci->max_rows))
00205     max_rows= ((((uint64_t) 1 << (pointer*8)) -1) / min_pack_length);
00206 
00207 
00208   real_reclength=reclength;
00209   if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
00210   {
00211     if (reclength <= pointer)
00212       reclength=pointer+1;    /* reserve place for delete link */
00213   }
00214   else
00215     reclength+= long_varchar_count; /* We need space for varchar! */
00216 
00217   max_key_length=0; tot_length=0 ; key_segs=0;
00218   fulltext_keys=0;
00219   max_key_block_length=0;
00220   share.state.rec_per_key_part=rec_per_key_part;
00221   share.state.key_root=key_root;
00222   share.state.key_del=key_del;
00223   if (uniques)
00224   {
00225     max_key_block_length= myisam_block_size;
00226     max_key_length=   MI_UNIQUE_HASH_LENGTH + pointer;
00227   }
00228 
00229   for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
00230   {
00231 
00232     share.state.key_root[i]= HA_OFFSET_ERROR;
00233     min_key_length_skip=length=real_length_diff=0;
00234     key_length=pointer;
00235     {
00236       /* Test if prefix compression */
00237       if (keydef->flag & HA_PACK_KEY)
00238       {
00239   /* Only use HA_PACK_KEY when first segment is a variable length key */
00240   if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
00241              HA_VAR_LENGTH_PART)))
00242   {
00243     /* pack relative to previous key */
00244     keydef->flag&= ~HA_PACK_KEY;
00245     keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
00246   }
00247   else
00248   {
00249     keydef->seg[0].flag|=HA_PACK_KEY; /* for easyer intern test */
00250     keydef->flag|=HA_VAR_LENGTH_KEY;
00251     options|=HA_OPTION_PACK_KEYS;   /* Using packed keys */
00252   }
00253       }
00254       if (keydef->flag & HA_BINARY_PACK_KEY)
00255   options|=HA_OPTION_PACK_KEYS;   /* Using packed keys */
00256 
00257       if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
00258   share.base.auto_key=i+1;
00259       for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
00260       {
00261   /* numbers are stored with high by first to make compression easier */
00262   switch (keyseg->type) {
00263   case HA_KEYTYPE_LONG_INT:
00264   case HA_KEYTYPE_DOUBLE:
00265   case HA_KEYTYPE_ULONG_INT:
00266   case HA_KEYTYPE_LONGLONG:
00267   case HA_KEYTYPE_ULONGLONG:
00268     keyseg->flag|= HA_SWAP_KEY;
00269           break;
00270         case HA_KEYTYPE_VARTEXT1:
00271         case HA_KEYTYPE_VARTEXT2:
00272         case HA_KEYTYPE_VARBINARY1:
00273         case HA_KEYTYPE_VARBINARY2:
00274           if (!(keyseg->flag & HA_BLOB_PART))
00275           {
00276             /* Make a flag that this is a VARCHAR */
00277             keyseg->flag|= HA_VAR_LENGTH_PART;
00278             /* Store in bit_start number of bytes used to pack the length */
00279             keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
00280                                  keyseg->type == HA_KEYTYPE_VARBINARY1) ?
00281                                 1 : 2);
00282           }
00283           break;
00284   default:
00285     break;
00286   }
00287   if (keyseg->flag & HA_SPACE_PACK)
00288   {
00289           assert(!(keyseg->flag & HA_VAR_LENGTH_PART));
00290     keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
00291     options|=HA_OPTION_PACK_KEYS;   /* Using packed keys */
00292     length++;       /* At least one length byte */
00293     min_key_length_skip+=keyseg->length;
00294     if (keyseg->length >= 255)
00295     {         /* prefix may be 3 bytes */
00296       min_key_length_skip+=2;
00297       length+=2;
00298     }
00299   }
00300   if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
00301   {
00302           assert(!test_all_bits(keyseg->flag,
00303                                     (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
00304     keydef->flag|=HA_VAR_LENGTH_KEY;
00305     length++;       /* At least one length byte */
00306     options|=HA_OPTION_PACK_KEYS;   /* Using packed keys */
00307     min_key_length_skip+=keyseg->length;
00308     if (keyseg->length >= 255)
00309     {         /* prefix may be 3 bytes */
00310       min_key_length_skip+=2;
00311       length+=2;
00312     }
00313   }
00314   key_length+= keyseg->length;
00315   if (keyseg->null_bit)
00316   {
00317     key_length++;
00318     options|=HA_OPTION_PACK_KEYS;
00319     keyseg->flag|=HA_NULL_PART;
00320     keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
00321   }
00322       }
00323     } /* if HA_FULLTEXT */
00324     key_segs+=keydef->keysegs;
00325     if (keydef->keysegs > MI_MAX_KEY_SEG)
00326     {
00327       errno=HA_WRONG_CREATE_OPTION;
00328       goto err;
00329     }
00330     /*
00331       key_segs may be 0 in the case when we only want to be able to
00332       add on row into the table. This can happen with some DISTINCT queries
00333       in MySQL
00334     */
00335     if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
00336   key_segs)
00337       share.state.rec_per_key_part[key_segs-1]=1L;
00338     length+=key_length;
00339     /* Get block length for key, if defined by user */
00340     block_length= (keydef->block_length ?
00341                    my_round_up_to_next_power(keydef->block_length) :
00342                    myisam_block_size);
00343     block_length= max(block_length, (uint32_t)MI_MIN_KEY_BLOCK_LENGTH);
00344     block_length= min(block_length, (uint32_t)MI_MAX_KEY_BLOCK_LENGTH);
00345 
00346     keydef->block_length= (uint16_t) MI_BLOCK_SIZE(length-real_length_diff,
00347                                                  pointer,MI_MAX_KEYPTR_SIZE,
00348                                                  block_length);
00349     if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
00350         length >= MI_MAX_KEY_BUFF)
00351     {
00352       errno=HA_WRONG_CREATE_OPTION;
00353       goto err;
00354     }
00355     set_if_bigger(max_key_block_length,(uint32_t)keydef->block_length);
00356     keydef->keylength= (uint16_t) key_length;
00357     keydef->minlength= (uint16_t) (length-min_key_length_skip);
00358     keydef->maxlength= (uint16_t) length;
00359 
00360     if (length > max_key_length)
00361       max_key_length= length;
00362     tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
00363             (length*2)))*
00364       (ulong) keydef->block_length;
00365   }
00366   for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
00367     key_del[i]=HA_OFFSET_ERROR;
00368 
00369   unique_key_parts=0;
00370   offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
00371   for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
00372   {
00373     uniquedef->key=keys+i;
00374     unique_key_parts+=uniquedef->keysegs;
00375     share.state.key_root[keys+i]= HA_OFFSET_ERROR;
00376     tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
00377                          ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
00378                          (ulong) myisam_block_size;
00379   }
00380   keys+=uniques;        /* Each unique has 1 key */
00381   key_segs+=uniques;        /* Each unique has 1 key seg */
00382 
00383   base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
00384       max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
00385       MI_STATE_KEYBLOCK_SIZE+
00386       key_segs*MI_STATE_KEYSEG_SIZE);
00387   info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
00388              keys * MI_KEYDEF_SIZE+
00389              uniques * MI_UNIQUEDEF_SIZE +
00390              (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
00391              columns*MI_COLUMNDEF_SIZE);
00392   /* There are only 16 bits for the total header length. */
00393   if (info_length > 65535)
00394   {
00395     my_printf_error(EE_OK, "MyISAM table '%s' has too many columns and/or "
00396                     "indexes and/or unique constraints.",
00397                     MYF(0), name + internal::dirname_length(name));
00398     errno= HA_WRONG_CREATE_OPTION;
00399     goto err;
00400   }
00401 
00402   memmove(share.state.header.file_version,myisam_file_magic,4);
00403   ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
00404       HA_OPTION_COMPRESS_RECORD |
00405       HA_OPTION_TEMP_COMPRESS_RECORD: 0);
00406   mi_int2store(share.state.header.options,ci->old_options);
00407   mi_int2store(share.state.header.header_length,info_length);
00408   mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
00409   mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
00410   mi_int2store(share.state.header.base_pos,base_pos);
00411   share.state.header.language= (ci->language ?
00412         ci->language : default_charset_info->number);
00413   share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
00414 
00415   share.state.dellink = HA_OFFSET_ERROR;
00416   share.state.process=  (ulong) getpid();
00417   share.state.unique= (ulong) 0;
00418   share.state.update_count=(ulong) 0;
00419   share.state.version=  (ulong) time((time_t*) 0);
00420   share.state.sortkey=  UINT16_MAX;
00421   share.state.auto_increment=ci->auto_increment;
00422   share.options=options;
00423   share.base.rec_reflength=pointer;
00424   /* Get estimate for index file length (this may be wrong for FT keys) */
00425   tmp= (tot_length + max_key_block_length * keys *
00426   MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
00427   /*
00428     use maximum of key_file_length we calculated and key_file_length value we
00429     got from MYI file header (see also myisampack.c:save_state)
00430   */
00431   share.base.key_reflength=
00432     mi_get_pointer_length(max(ci->key_file_length,tmp),3);
00433   share.base.keys= share.state.header.keys= keys;
00434   share.state.header.uniques= uniques;
00435   share.state.header.fulltext_keys= fulltext_keys;
00436   mi_int2store(share.state.header.key_parts,key_segs);
00437   mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
00438 
00439   mi_set_all_keys_active(share.state.key_map, keys);
00440   aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
00441                                                max_key_block_length :
00442                                                myisam_block_size);
00443 
00444   share.base.keystart= share.state.state.key_file_length=
00445     MY_ALIGN(info_length, aligned_key_start);
00446   share.base.max_key_block_length=max_key_block_length;
00447   share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
00448   share.base.records=ci->max_rows;
00449   share.base.reloc=  ci->reloc_rows;
00450   share.base.reclength=real_reclength;
00451   share.base.pack_reclength=reclength;
00452   share.base.max_pack_length=pack_reclength;
00453   share.base.min_pack_length=min_pack_length;
00454   share.base.pack_bits=packed;
00455   share.base.fields=fields;
00456   share.base.pack_fields=packed;
00457 
00458   /* max_data_file_length and max_key_file_length are recalculated on open */
00459   if (options & HA_OPTION_TMP_TABLE)
00460     share.base.max_data_file_length=(internal::my_off_t) ci->data_file_length;
00461 
00462   share.base.min_block_length=
00463     (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
00464      ! share.base.blobs) ?
00465     max(share.base.pack_reclength,(ulong)MI_MIN_BLOCK_LENGTH) :
00466     MI_EXTEND_BLOCK_LENGTH;
00467   if (! (flags & HA_DONT_TOUCH_DATA))
00468     share.state.create_time= (long) time((time_t*) 0);
00469 
00470   THR_LOCK_myisam.lock();
00471 
00472   /*
00473     NOTE: For test_if_reopen() we need a real path name. Hence we need
00474     MY_RETURN_REAL_PATH for every internal::fn_format(filename, ...).
00475   */
00476   if (ci->index_file_name)
00477   {
00478     char *iext= strrchr((char *)ci->index_file_name, '.');
00479     int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
00480     if (options & HA_OPTION_TMP_TABLE)
00481     {
00482       char *path;
00483       /* chop off the table name, tempory tables use generated name */
00484       if ((path= strrchr((char *)ci->index_file_name, FN_LIBCHAR)))
00485         *path= '\0';
00486       internal::fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT,
00487                 MY_REPLACE_DIR | MY_UNPACK_FILENAME |
00488                 MY_RETURN_REAL_PATH | MY_APPEND_EXT);
00489     }
00490     else
00491     {
00492       internal::fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT,
00493                 MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
00494                 (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
00495     }
00496     internal::fn_format(linkname, name, "", MI_NAME_IEXT,
00497               MY_UNPACK_FILENAME|MY_APPEND_EXT);
00498     linkname_ptr=linkname;
00499     /*
00500       Don't create the table if the link or file exists to ensure that one
00501       doesn't accidently destroy another table.
00502     */
00503     create_flag=0;
00504   }
00505   else
00506   {
00507     char *iext= strrchr((char *)name, '.');
00508     int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
00509     internal::fn_format(filename, name, "", MI_NAME_IEXT,
00510               MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
00511               (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
00512     linkname_ptr=0;
00513     /* Replace the current file */
00514     create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
00515   }
00516 
00517   /*
00518     If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
00519     but no entry is made in the table cache for them.
00520     A TRUNCATE command checks for the table in the cache only and could
00521     be fooled to believe, the table is not open.
00522     Pull the emergency brake in this situation. (Bug #8306)
00523 
00524     NOTE: The filename is compared against unique_file_name of every
00525     open table. Hence we need a real path here.
00526   */
00527   if (test_if_reopen(filename))
00528   {
00529     my_printf_error(EE_OK, "MyISAM table '%s' is in use "
00530                     "(most likely by a MERGE table). Try FLUSH TABLES.",
00531                     MYF(0), name + internal::dirname_length(name));
00532     errno= HA_ERR_TABLE_EXIST;
00533     goto err;
00534   }
00535 
00536   if ((file= internal::my_create_with_symlink(linkname_ptr,
00537                                               filename,
00538                                               0,
00539                                               create_mode,
00540                       MYF(MY_WME | create_flag))) < 0)
00541     goto err;
00542   errpos=1;
00543 
00544   if (!(flags & HA_DONT_TOUCH_DATA))
00545   {
00546     {
00547       if (ci->data_file_name)
00548       {
00549         char *dext= strrchr((char *)ci->data_file_name, '.');
00550         int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);
00551 
00552         if (options & HA_OPTION_TMP_TABLE)
00553         {
00554           char *path;
00555           /* chop off the table name, tempory tables use generated name */
00556           if ((path= strrchr((char *)ci->data_file_name, FN_LIBCHAR)))
00557             *path= '\0';
00558           internal::fn_format(filename, name, ci->data_file_name, MI_NAME_DEXT,
00559                     MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
00560         }
00561         else
00562         {
00563           internal::fn_format(filename, ci->data_file_name, "", MI_NAME_DEXT,
00564                     MY_UNPACK_FILENAME |
00565                     (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
00566         }
00567 
00568   internal::fn_format(linkname, name, "",MI_NAME_DEXT,
00569             MY_UNPACK_FILENAME | MY_APPEND_EXT);
00570   linkname_ptr=linkname;
00571   create_flag=0;
00572       }
00573       else
00574       {
00575   internal::fn_format(filename,name,"", MI_NAME_DEXT,
00576             MY_UNPACK_FILENAME | MY_APPEND_EXT);
00577   linkname_ptr=0;
00578         create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
00579       }
00580       if ((dfile= internal::my_create_with_symlink(linkname_ptr,
00581                                                    filename, 0, create_mode,
00582                                                    MYF(MY_WME | create_flag))) < 0)
00583   goto err;
00584     }
00585     errpos=3;
00586   }
00587 
00588   if (mi_state_info_write(file, &share.state, 2) ||
00589       mi_base_info_write(file, &share.base))
00590     goto err;
00591 
00592   /* Write key and keyseg definitions */
00593   for (i=0 ; i < share.base.keys - uniques; i++)
00594   {
00595     uint32_t sp_segs= 0;
00596 
00597     if (mi_keydef_write(file, &keydefs[i]))
00598       goto err;
00599     for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
00600       if (mi_keyseg_write(file, &keydefs[i].seg[j]))
00601        goto err;
00602   }
00603   /* Create extra keys for unique definitions */
00604   offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
00605   memset(&tmp_keydef, 0, sizeof(tmp_keydef));
00606   memset(&tmp_keyseg, 0, sizeof(tmp_keyseg));
00607   for (i=0; i < uniques ; i++)
00608   {
00609     tmp_keydef.keysegs=1;
00610     tmp_keydef.flag=    HA_UNIQUE_CHECK;
00611     tmp_keydef.block_length=  (uint16_t)myisam_block_size;
00612     tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer;
00613     tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
00614     tmp_keyseg.type=    MI_UNIQUE_HASH_TYPE;
00615     tmp_keyseg.length=    MI_UNIQUE_HASH_LENGTH;
00616     tmp_keyseg.start=   offset;
00617     offset+=      MI_UNIQUE_HASH_LENGTH;
00618     if (mi_keydef_write(file,&tmp_keydef) ||
00619   mi_keyseg_write(file,(&tmp_keyseg)))
00620       goto err;
00621   }
00622 
00623   /* Save unique definition */
00624   for (i=0 ; i < share.state.header.uniques ; i++)
00625   {
00626     HA_KEYSEG *keyseg_end;
00627     keyseg= uniquedefs[i].seg;
00628     if (mi_uniquedef_write(file, &uniquedefs[i]))
00629       goto err;
00630     for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
00631          keyseg < keyseg_end;
00632          keyseg++)
00633     {
00634       switch (keyseg->type) {
00635       case HA_KEYTYPE_VARTEXT1:
00636       case HA_KEYTYPE_VARTEXT2:
00637       case HA_KEYTYPE_VARBINARY1:
00638       case HA_KEYTYPE_VARBINARY2:
00639         if (!(keyseg->flag & HA_BLOB_PART))
00640         {
00641           keyseg->flag|= HA_VAR_LENGTH_PART;
00642           keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
00643                                keyseg->type == HA_KEYTYPE_VARBINARY1) ?
00644                               1 : 2);
00645         }
00646         break;
00647       default:
00648         break;
00649       }
00650       if (mi_keyseg_write(file, keyseg))
00651   goto err;
00652     }
00653   }
00654   for (i=0 ; i < share.base.fields ; i++)
00655     if (mi_recinfo_write(file, &recinfo[i]))
00656       goto err;
00657 
00658   /* Enlarge files */
00659   if (ftruncate(file, (off_t) share.base.keystart))
00660     goto err;
00661 
00662   if (! (flags & HA_DONT_TOUCH_DATA))
00663   {
00664 #ifdef USE_RELOC
00665     if (ftruncate(dfile,share.base.min_pack_length*ci->reloc_rows,))
00666       goto err;
00667 #endif
00668     errpos=2;
00669     if (internal::my_close(dfile,MYF(0)))
00670       goto err;
00671   }
00672   errpos=0;
00673   THR_LOCK_myisam.unlock();
00674   if (internal::my_close(file,MYF(0)))
00675     goto err;
00676   free((char*) rec_per_key_part);
00677   return(0);
00678 
00679 err:
00680   THR_LOCK_myisam.unlock();
00681   save_errno=errno;
00682   switch (errpos) {
00683   case 3:
00684     internal::my_close(dfile,MYF(0));
00685     /* fall through */
00686   case 2:
00687   if (! (flags & HA_DONT_TOUCH_DATA))
00688     internal::my_delete_with_symlink(internal::fn_format(filename,name,"",MI_NAME_DEXT,
00689                                      MY_UNPACK_FILENAME | MY_APPEND_EXT),
00690          MYF(0));
00691     /* fall through */
00692   case 1:
00693     internal::my_close(file,MYF(0));
00694     if (! (flags & HA_DONT_TOUCH_DATA))
00695       internal::my_delete_with_symlink(internal::fn_format(filename,name,"",MI_NAME_IEXT,
00696                                        MY_UNPACK_FILENAME | MY_APPEND_EXT),
00697            MYF(0));
00698   }
00699   free((char*) rec_per_key_part);
00700   return(errno=save_errno);   /* return the fatal errno */
00701 }
00702 
00703 
00704 uint32_t mi_get_pointer_length(uint64_t file_length, uint32_t def)
00705 {
00706   assert(def >= 2 && def <= 7);
00707   if (file_length)        /* If not default */
00708   {
00709 #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
00710     if (file_length >= 1ULL << 56)
00711       def=8;
00712     else
00713 #endif
00714     if (file_length >= 1ULL << 48)
00715       def=7;
00716     else if (file_length >= 1ULL << 40)
00717       def=6;
00718     else if (file_length >= 1ULL << 32)
00719       def=5;
00720     else if (file_length >= 1ULL << 24)
00721       def=4;
00722     else if (file_length >= 1ULL << 16)
00723       def=3;
00724     else
00725       def=2;
00726   }
00727   return def;
00728 }