Drizzled Public API Documentation

mi_create.cc
1 /* Copyright (C) 2000-2006 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* Create a MyISAM table */
17 
18 #include "myisam_priv.h"
19 #include <drizzled/internal/my_bit.h>
20 #include <drizzled/internal/my_sys.h>
21 
22 #include <drizzled/util/test.h>
23 #include <drizzled/charset.h>
24 #include <drizzled/error.h>
25 
26 #include <cassert>
27 #include <algorithm>
28 
29 using namespace std;
30 using namespace drizzled;
31 
32 /*
33  Next highest power of two
34 
35  SYNOPSIS
36  my_round_up_to_next_power()
37  v Value to check
38 
39  RETURN
40  Next or equal power of 2
41  Note: 0 will return 0
42 
43  NOTES
44  Algorithm by Sean Anderson, according to:
45  http://graphics.stanford.edu/~seander/bithacks.html
46  (Orignal code public domain)
47 
48  Comments shows how this works with 01100000000000000000000000001011
49 */
50 
51 static inline uint32_t my_round_up_to_next_power(uint32_t v)
52 {
53  v--; /* 01100000000000000000000000001010 */
54  v|= v >> 1; /* 01110000000000000000000000001111 */
55  v|= v >> 2; /* 01111100000000000000000000001111 */
56  v|= v >> 4; /* 01111111110000000000000000001111 */
57  v|= v >> 8; /* 01111111111111111100000000001111 */
58  v|= v >> 16; /* 01111111111111111111111111111111 */
59  return v+1; /* 10000000000000000000000000000000 */
60 }
61 
62 /*
63  Old options is used when recreating database, from myisamchk
64 */
65 
66 int mi_create(const char *name,uint32_t keys,MI_KEYDEF *keydefs,
67  uint32_t columns, MI_COLUMNDEF *recinfo,
68  uint32_t uniques, MI_UNIQUEDEF *uniquedefs,
69  MI_CREATE_INFO *ci,uint32_t flags)
70 {
71  register uint32_t i, j;
72  int dfile= 0, file= 0;
73  int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
74  myf create_flag;
75  uint32_t fields,length,max_key_length,packed,pointer,real_length_diff,
76  key_length,info_length,key_segs,options,min_key_length_skip,
77  base_pos,long_varchar_count,varchar_length,
78  max_key_block_length,unique_key_parts,fulltext_keys,offset;
79  uint32_t aligned_key_start, block_length;
80  ulong reclength, real_reclength,min_pack_length;
81  char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
82  ulong pack_reclength;
83  uint64_t tot_length,max_rows, tmp;
84  enum en_fieldtype type;
85  MYISAM_SHARE share;
86  MI_KEYDEF *keydef,tmp_keydef;
87  MI_UNIQUEDEF *uniquedef;
88  HA_KEYSEG *keyseg,tmp_keyseg;
89  MI_COLUMNDEF *rec;
90  ulong *rec_per_key_part;
91  internal::my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
92  MI_CREATE_INFO tmp_create_info;
93 
94  if (!ci)
95  {
96  memset(&tmp_create_info, 0, sizeof(tmp_create_info));
97  ci=&tmp_create_info;
98  }
99 
100  if (keys + uniques > MI_MAX_KEY || columns == 0)
101  {
102  return(errno=HA_WRONG_CREATE_OPTION);
103  }
104  errpos= 0;
105  options= 0;
106  memset(&share, 0, sizeof(share));
107 
108  if (flags & HA_DONT_TOUCH_DATA)
109  {
110  if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
111  options=ci->old_options &
112  (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
113  HA_OPTION_READ_ONLY_DATA |
114  HA_OPTION_TMP_TABLE );
115  else
116  options=ci->old_options &
117  (HA_OPTION_TMP_TABLE );
118  }
119 
120  if (ci->reloc_rows > ci->max_rows)
121  ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */
122 
123  if (!(rec_per_key_part=
124  (ulong*) malloc((keys + uniques)*MI_MAX_KEY_SEG*sizeof(long))))
125  return(errno);
126  memset(rec_per_key_part, 0, (keys + uniques)*MI_MAX_KEY_SEG*sizeof(long));
127 
128  /* Start by checking fields and field-types used */
129 
130  reclength=varchar_length=long_varchar_count=packed=
131  min_pack_length=pack_reclength=0;
132  for (rec=recinfo, fields=0 ;
133  fields != columns ;
134  rec++,fields++)
135  {
136  reclength+=rec->length;
137  if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
138  type != FIELD_CHECK)
139  {
140  packed++;
141  if (type == FIELD_BLOB)
142  {
143  share.base.blobs++;
144  if (pack_reclength != INT32_MAX)
145  {
146  if (rec->length == 4+portable_sizeof_char_ptr)
147  pack_reclength= INT32_MAX;
148  else
149  pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */
150  }
151  }
152  else if (type == FIELD_SKIP_PRESPACE ||
153  type == FIELD_SKIP_ENDSPACE)
154  {
155  if (pack_reclength != INT32_MAX)
156  pack_reclength+= rec->length > 255 ? 2 : 1;
157  min_pack_length++;
158  }
159  else if (type == FIELD_VARCHAR)
160  {
161  varchar_length+= rec->length-1; /* Used for min_pack_length */
162  packed--;
163  pack_reclength++;
164  min_pack_length++;
165  /* We must test for 257 as length includes pack-length */
166  if (test(rec->length >= 257))
167  {
168  long_varchar_count++;
169  pack_reclength+= 2; /* May be packed on 3 bytes */
170  }
171  }
172  else if (type != FIELD_SKIP_ZERO)
173  {
174  min_pack_length+=rec->length;
175  packed--; /* Not a pack record type */
176  }
177  }
178  else /* FIELD_NORMAL */
179  min_pack_length+=rec->length;
180  }
181  if ((packed & 7) == 1)
182  { /* Bad packing, try to remove a zero-field */
183  while (rec != recinfo)
184  {
185  rec--;
186  if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
187  {
188  /*
189  NOTE1: here we change a field type FIELD_SKIP_ZERO ->
190  FIELD_NORMAL
191  */
192  rec->type=(int) FIELD_NORMAL;
193  packed--;
194  min_pack_length++;
195  break;
196  }
197  }
198  }
199 
200  if (packed || (flags & HA_PACK_RECORD))
201  options|=HA_OPTION_PACK_RECORD; /* Must use packed records */
202  if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
203  min_pack_length+= varchar_length;
204  if (flags & HA_CREATE_TMP_TABLE)
205  {
206  options|= HA_OPTION_TMP_TABLE;
207  create_mode|= O_EXCL;
208  }
209 
210  packed=(packed+7)/8;
211  if (pack_reclength != INT32_MAX)
212  pack_reclength+= reclength+packed +
213  test(test_all_bits(options,
214  uint32_t(HA_PACK_RECORD)));
215  min_pack_length+=packed;
216 
217  if (!ci->data_file_length && ci->max_rows)
218  {
219  if (pack_reclength == INT32_MAX ||
220  (~(uint64_t) 0)/ci->max_rows < (uint64_t) pack_reclength)
221  ci->data_file_length= ~(uint64_t) 0;
222  else
223  ci->data_file_length=(uint64_t) ci->max_rows*pack_reclength;
224  }
225  else if (!ci->max_rows)
226  ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
227  ((options & HA_OPTION_PACK_RECORD) ?
228  3 : 0)));
229 
230  if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
231  pointer=mi_get_pointer_length(ci->data_file_length, data_pointer_size);
232  else
233  pointer=mi_get_pointer_length(ci->max_rows, data_pointer_size);
234  if (!(max_rows=(uint64_t) ci->max_rows))
235  max_rows= ((((uint64_t) 1 << (pointer*8)) -1) / min_pack_length);
236 
237 
238  real_reclength=reclength;
239  if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
240  {
241  if (reclength <= pointer)
242  reclength=pointer+1; /* reserve place for delete link */
243  }
244  else
245  reclength+= long_varchar_count; /* We need space for varchar! */
246 
247  max_key_length=0; tot_length=0 ; key_segs=0;
248  fulltext_keys=0;
249  max_key_block_length=0;
250  share.state.rec_per_key_part=rec_per_key_part;
251  share.state.key_root=key_root;
252  share.state.key_del=key_del;
253  if (uniques)
254  {
255  max_key_block_length= myisam_block_size;
256  max_key_length= MI_UNIQUE_HASH_LENGTH + pointer;
257  }
258 
259  for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
260  {
261 
262  share.state.key_root[i]= HA_OFFSET_ERROR;
263  min_key_length_skip=length=real_length_diff=0;
264  key_length=pointer;
265  {
266  /* Test if prefix compression */
267  if (keydef->flag & HA_PACK_KEY)
268  {
269  /* Only use HA_PACK_KEY when first segment is a variable length key */
270  if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
271  HA_VAR_LENGTH_PART)))
272  {
273  /* pack relative to previous key */
274  keydef->flag&= ~HA_PACK_KEY;
275  keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
276  }
277  else
278  {
279  keydef->seg[0].flag|=HA_PACK_KEY; /* for easyer intern test */
280  keydef->flag|=HA_VAR_LENGTH_KEY;
281  options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
282  }
283  }
284  if (keydef->flag & HA_BINARY_PACK_KEY)
285  options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
286 
287  if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
288  share.base.auto_key=i+1;
289  for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
290  {
291  /* numbers are stored with high by first to make compression easier */
292  switch (keyseg->type) {
293  case HA_KEYTYPE_LONG_INT:
294  case HA_KEYTYPE_DOUBLE:
295  case HA_KEYTYPE_ULONG_INT:
296  case HA_KEYTYPE_LONGLONG:
297  case HA_KEYTYPE_ULONGLONG:
298  keyseg->flag|= HA_SWAP_KEY;
299  break;
300  case HA_KEYTYPE_VARTEXT1:
301  case HA_KEYTYPE_VARTEXT2:
302  case HA_KEYTYPE_VARBINARY1:
303  case HA_KEYTYPE_VARBINARY2:
304  if (!(keyseg->flag & HA_BLOB_PART))
305  {
306  /* Make a flag that this is a VARCHAR */
307  keyseg->flag|= HA_VAR_LENGTH_PART;
308  /* Store in bit_start number of bytes used to pack the length */
309  keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
310  keyseg->type == HA_KEYTYPE_VARBINARY1) ?
311  1 : 2);
312  }
313  break;
314  default:
315  break;
316  }
317  if (keyseg->flag & HA_SPACE_PACK)
318  {
319  assert(!(keyseg->flag & HA_VAR_LENGTH_PART));
320  keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
321  options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
322  length++; /* At least one length byte */
323  min_key_length_skip+=keyseg->length;
324  if (keyseg->length >= 255)
325  { /* prefix may be 3 bytes */
326  min_key_length_skip+=2;
327  length+=2;
328  }
329  }
330  if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
331  {
332  assert(!test_all_bits(keyseg->flag,
333  (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
334  keydef->flag|=HA_VAR_LENGTH_KEY;
335  length++; /* At least one length byte */
336  options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
337  min_key_length_skip+=keyseg->length;
338  if (keyseg->length >= 255)
339  { /* prefix may be 3 bytes */
340  min_key_length_skip+=2;
341  length+=2;
342  }
343  }
344  key_length+= keyseg->length;
345  if (keyseg->null_bit)
346  {
347  key_length++;
348  options|=HA_OPTION_PACK_KEYS;
349  keyseg->flag|=HA_NULL_PART;
350  keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
351  }
352  }
353  } /* if HA_FULLTEXT */
354  key_segs+=keydef->keysegs;
355  if (keydef->keysegs > MI_MAX_KEY_SEG)
356  {
357  errno=HA_WRONG_CREATE_OPTION;
358  goto err;
359  }
360  /*
361  key_segs may be 0 in the case when we only want to be able to
362  add on row into the table. This can happen with some DISTINCT queries
363  in MySQL
364  */
365  if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
366  key_segs)
367  share.state.rec_per_key_part[key_segs-1]=1L;
368  length+=key_length;
369  /* Get block length for key, if defined by user */
370  block_length= (keydef->block_length ?
371  my_round_up_to_next_power(keydef->block_length) :
372  myisam_block_size);
373  block_length= max(block_length, (uint32_t)MI_MIN_KEY_BLOCK_LENGTH);
374  block_length= min(block_length, (uint32_t)MI_MAX_KEY_BLOCK_LENGTH);
375 
376  keydef->block_length= (uint16_t) MI_BLOCK_SIZE(length-real_length_diff,
377  pointer,MI_MAX_KEYPTR_SIZE,
378  block_length);
379  if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
380  length >= MI_MAX_KEY_BUFF)
381  {
382  errno=HA_WRONG_CREATE_OPTION;
383  goto err;
384  }
385  set_if_bigger(max_key_block_length,(uint32_t)keydef->block_length);
386  keydef->keylength= (uint16_t) key_length;
387  keydef->minlength= (uint16_t) (length-min_key_length_skip);
388  keydef->maxlength= (uint16_t) length;
389 
390  if (length > max_key_length)
391  max_key_length= length;
392  tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
393  (length*2)))*
394  (ulong) keydef->block_length;
395  }
396  for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
397  key_del[i]=HA_OFFSET_ERROR;
398 
399  unique_key_parts=0;
400  offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
401  for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
402  {
403  uniquedef->key=keys+i;
404  unique_key_parts+=uniquedef->keysegs;
405  share.state.key_root[keys+i]= HA_OFFSET_ERROR;
406  tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
407  ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
408  (ulong) myisam_block_size;
409  }
410  keys+=uniques; /* Each unique has 1 key */
411  key_segs+=uniques; /* Each unique has 1 key seg */
412 
413  base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
414  max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
415  MI_STATE_KEYBLOCK_SIZE+
416  key_segs*MI_STATE_KEYSEG_SIZE);
417  info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
418  keys * MI_KEYDEF_SIZE+
419  uniques * MI_UNIQUEDEF_SIZE +
420  (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
421  columns*MI_COLUMNDEF_SIZE);
422  /* There are only 16 bits for the total header length. */
423  if (info_length > 65535)
424  {
425  my_printf_error(EE_OK, "MyISAM table '%s' has too many columns and/or "
426  "indexes and/or unique constraints.",
427  MYF(0), name + internal::dirname_length(name));
428  errno= HA_WRONG_CREATE_OPTION;
429  goto err;
430  }
431 
432  memmove(share.state.header.file_version,myisam_file_magic,4);
433  ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
434  HA_OPTION_COMPRESS_RECORD |
435  HA_OPTION_TEMP_COMPRESS_RECORD: 0);
436  mi_int2store(share.state.header.options,ci->old_options);
437  mi_int2store(share.state.header.header_length,info_length);
438  mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
439  mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
440  mi_int2store(share.state.header.base_pos,base_pos);
441  share.state.header.language= (ci->language ?
442  ci->language : default_charset_info->number);
443  share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
444 
445  share.state.dellink = HA_OFFSET_ERROR;
446  share.state.process= (ulong) getpid();
447  share.state.unique= (ulong) 0;
448  share.state.update_count=(ulong) 0;
449  share.state.version= (ulong) time((time_t*) 0);
450  share.state.sortkey= UINT16_MAX;
451  share.state.auto_increment=ci->auto_increment;
452  share.options=options;
453  share.base.rec_reflength=pointer;
454  /* Get estimate for index file length (this may be wrong for FT keys) */
455  tmp= (tot_length + max_key_block_length * keys *
456  MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
457  /*
458  use maximum of key_file_length we calculated and key_file_length value we
459  got from MYI file header (see also myisampack.c:save_state)
460  */
461  share.base.key_reflength=
462  mi_get_pointer_length(max(ci->key_file_length,tmp),3);
463  share.base.keys= share.state.header.keys= keys;
464  share.state.header.uniques= uniques;
465  share.state.header.fulltext_keys= fulltext_keys;
466  mi_int2store(share.state.header.key_parts,key_segs);
467  mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
468 
469  mi_set_all_keys_active(share.state.key_map, keys);
470  aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
471  max_key_block_length :
472  myisam_block_size);
473 
474  share.base.keystart= share.state.state.key_file_length=
475  MY_ALIGN(info_length, aligned_key_start);
476  share.base.max_key_block_length=max_key_block_length;
477  share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
478  share.base.records=ci->max_rows;
479  share.base.reloc= ci->reloc_rows;
480  share.base.reclength=real_reclength;
481  share.base.pack_reclength=reclength;
482  share.base.max_pack_length=pack_reclength;
483  share.base.min_pack_length=min_pack_length;
484  share.base.pack_bits=packed;
485  share.base.fields=fields;
486  share.base.pack_fields=packed;
487 
488  /* max_data_file_length and max_key_file_length are recalculated on open */
489  if (options & HA_OPTION_TMP_TABLE)
490  share.base.max_data_file_length=(internal::my_off_t) ci->data_file_length;
491 
492  share.base.min_block_length=
493  (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
494  ! share.base.blobs) ?
495  max(share.base.pack_reclength,(ulong)MI_MIN_BLOCK_LENGTH) :
496  MI_EXTEND_BLOCK_LENGTH;
497  if (! (flags & HA_DONT_TOUCH_DATA))
498  share.state.create_time= (long) time((time_t*) 0);
499 
500  THR_LOCK_myisam.lock();
501 
502  /*
503  NOTE: For test_if_reopen() we need a real path name. Hence we need
504  MY_RETURN_REAL_PATH for every internal::fn_format(filename, ...).
505  */
506  if (ci->index_file_name)
507  {
508  char *iext= strrchr((char *)ci->index_file_name, '.');
509  int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
510  if (options & HA_OPTION_TMP_TABLE)
511  {
512  char *path;
513  /* chop off the table name, tempory tables use generated name */
514  if ((path= strrchr((char *)ci->index_file_name, FN_LIBCHAR)))
515  *path= '\0';
516  internal::fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT,
517  MY_REPLACE_DIR | MY_UNPACK_FILENAME |
518  MY_RETURN_REAL_PATH | MY_APPEND_EXT);
519  }
520  else
521  {
522  internal::fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT,
523  MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
524  (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
525  }
526  internal::fn_format(linkname, name, "", MI_NAME_IEXT,
527  MY_UNPACK_FILENAME|MY_APPEND_EXT);
528  linkname_ptr=linkname;
529  /*
530  Don't create the table if the link or file exists to ensure that one
531  doesn't accidently destroy another table.
532  */
533  create_flag=0;
534  }
535  else
536  {
537  char *iext= strrchr((char *)name, '.');
538  int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
539  internal::fn_format(filename, name, "", MI_NAME_IEXT,
540  MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
541  (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
542  linkname_ptr=0;
543  /* Replace the current file */
544  create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
545  }
546 
547  /*
548  If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
549  but no entry is made in the table cache for them.
550  A TRUNCATE command checks for the table in the cache only and could
551  be fooled to believe, the table is not open.
552  Pull the emergency brake in this situation. (Bug #8306)
553 
554  NOTE: The filename is compared against unique_file_name of every
555  open table. Hence we need a real path here.
556  */
557  if (test_if_reopen(filename))
558  {
559  my_printf_error(EE_OK, "MyISAM table '%s' is in use "
560  "(most likely by a MERGE table). Try FLUSH TABLES.",
561  MYF(0), name + internal::dirname_length(name));
562  errno= HA_ERR_TABLE_EXIST;
563  goto err;
564  }
565 
566  if ((file= internal::my_create_with_symlink(linkname_ptr,
567  filename,
568  0,
569  create_mode,
570  MYF(MY_WME | create_flag))) < 0)
571  goto err;
572  errpos=1;
573 
574  if (!(flags & HA_DONT_TOUCH_DATA))
575  {
576  {
577  if (ci->data_file_name)
578  {
579  char *dext= strrchr((char *)ci->data_file_name, '.');
580  int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);
581 
582  if (options & HA_OPTION_TMP_TABLE)
583  {
584  char *path;
585  /* chop off the table name, tempory tables use generated name */
586  if ((path= strrchr((char *)ci->data_file_name, FN_LIBCHAR)))
587  *path= '\0';
588  internal::fn_format(filename, name, ci->data_file_name, MI_NAME_DEXT,
589  MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
590  }
591  else
592  {
593  internal::fn_format(filename, ci->data_file_name, "", MI_NAME_DEXT,
594  MY_UNPACK_FILENAME |
595  (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
596  }
597 
598  internal::fn_format(linkname, name, "",MI_NAME_DEXT,
599  MY_UNPACK_FILENAME | MY_APPEND_EXT);
600  linkname_ptr=linkname;
601  create_flag=0;
602  }
603  else
604  {
605  internal::fn_format(filename,name,"", MI_NAME_DEXT,
606  MY_UNPACK_FILENAME | MY_APPEND_EXT);
607  linkname_ptr=0;
608  create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
609  }
610  if ((dfile= internal::my_create_with_symlink(linkname_ptr,
611  filename, 0, create_mode,
612  MYF(MY_WME | create_flag))) < 0)
613  goto err;
614  }
615  errpos=3;
616  }
617 
618  if (mi_state_info_write(file, &share.state, 2) ||
619  mi_base_info_write(file, &share.base))
620  goto err;
621 
622  /* Write key and keyseg definitions */
623  for (i=0 ; i < share.base.keys - uniques; i++)
624  {
625  uint32_t sp_segs= 0;
626 
627  if (mi_keydef_write(file, &keydefs[i]))
628  goto err;
629  for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
630  if (mi_keyseg_write(file, &keydefs[i].seg[j]))
631  goto err;
632  }
633  /* Create extra keys for unique definitions */
634  offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
635  memset(&tmp_keydef, 0, sizeof(tmp_keydef));
636  memset(&tmp_keyseg, 0, sizeof(tmp_keyseg));
637  for (i=0; i < uniques ; i++)
638  {
639  tmp_keydef.keysegs=1;
640  tmp_keydef.flag= HA_UNIQUE_CHECK;
641  tmp_keydef.block_length= (uint16_t)myisam_block_size;
642  tmp_keydef.keylength= MI_UNIQUE_HASH_LENGTH + pointer;
643  tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
644  tmp_keyseg.type= MI_UNIQUE_HASH_TYPE;
645  tmp_keyseg.length= MI_UNIQUE_HASH_LENGTH;
646  tmp_keyseg.start= offset;
647  offset+= MI_UNIQUE_HASH_LENGTH;
648  if (mi_keydef_write(file,&tmp_keydef) ||
649  mi_keyseg_write(file,(&tmp_keyseg)))
650  goto err;
651  }
652 
653  /* Save unique definition */
654  for (i=0 ; i < share.state.header.uniques ; i++)
655  {
656  HA_KEYSEG *keyseg_end;
657  keyseg= uniquedefs[i].seg;
658  if (mi_uniquedef_write(file, &uniquedefs[i]))
659  goto err;
660  for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
661  keyseg < keyseg_end;
662  keyseg++)
663  {
664  switch (keyseg->type) {
665  case HA_KEYTYPE_VARTEXT1:
666  case HA_KEYTYPE_VARTEXT2:
667  case HA_KEYTYPE_VARBINARY1:
668  case HA_KEYTYPE_VARBINARY2:
669  if (!(keyseg->flag & HA_BLOB_PART))
670  {
671  keyseg->flag|= HA_VAR_LENGTH_PART;
672  keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
673  keyseg->type == HA_KEYTYPE_VARBINARY1) ?
674  1 : 2);
675  }
676  break;
677  default:
678  break;
679  }
680  if (mi_keyseg_write(file, keyseg))
681  goto err;
682  }
683  }
684  for (i=0 ; i < share.base.fields ; i++)
685  if (mi_recinfo_write(file, &recinfo[i]))
686  goto err;
687 
688  /* Enlarge files */
689  if (ftruncate(file, (off_t) share.base.keystart))
690  goto err;
691 
692  if (! (flags & HA_DONT_TOUCH_DATA))
693  {
694 #ifdef USE_RELOC
695  if (ftruncate(dfile,share.base.min_pack_length*ci->reloc_rows,))
696  goto err;
697 #endif
698  errpos=2;
699  if (internal::my_close(dfile,MYF(0)))
700  goto err;
701  }
702  errpos=0;
703  THR_LOCK_myisam.unlock();
704  if (internal::my_close(file,MYF(0)))
705  goto err;
706  free((char*) rec_per_key_part);
707  return(0);
708 
709 err:
710  THR_LOCK_myisam.unlock();
711  save_errno=errno;
712  switch (errpos) {
713  case 3:
714  internal::my_close(dfile,MYF(0));
715  /* fall through */
716  case 2:
717  if (! (flags & HA_DONT_TOUCH_DATA))
718  internal::my_delete_with_symlink(internal::fn_format(filename,name,"",MI_NAME_DEXT,
719  MY_UNPACK_FILENAME | MY_APPEND_EXT),
720  MYF(0));
721  /* fall through */
722  case 1:
723  internal::my_close(file,MYF(0));
724  if (! (flags & HA_DONT_TOUCH_DATA))
725  internal::my_delete_with_symlink(internal::fn_format(filename,name,"",MI_NAME_IEXT,
726  MY_UNPACK_FILENAME | MY_APPEND_EXT),
727  MYF(0));
728  }
729  free((char*) rec_per_key_part);
730  return(errno=save_errno); /* return the fatal errno */
731 }
732 
733 
734 uint32_t mi_get_pointer_length(uint64_t file_length, uint32_t def)
735 {
736  assert(def >= 2 && def <= 7);
737  if (file_length) /* If not default */
738  {
739 #ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
740  if (file_length >= 1ULL << 56)
741  def=8;
742  else
743 #endif
744  if (file_length >= 1ULL << 48)
745  def=7;
746  else if (file_length >= 1ULL << 40)
747  def=6;
748  else if (file_length >= 1ULL << 32)
749  def=5;
750  else if (file_length >= 1ULL << 24)
751  def=4;
752  else if (file_length >= 1ULL << 16)
753  def=3;
754  else
755  def=2;
756  }
757  return def;
758 }