mi_create.c 28.9 KB
Newer Older
1
/*
2
   Copyright (c) 2000, 2011, Oracle and/or its affiliates
3
   Copyright (c) 2009, 2013, Monty Program Ab.
unknown's avatar
unknown committed
4

unknown's avatar
unknown committed
5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
7
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
8

unknown's avatar
unknown committed
9 10 11 12
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
13

unknown's avatar
unknown committed
14 15
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
Vicențiu Ciorbaru's avatar
Vicențiu Ciorbaru committed
16
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
unknown's avatar
unknown committed
17 18 19

/* Create a MyISAM table */

20
#include "ftdefs.h"
21
#include "sp_defs.h"
22
#include <my_bit.h>
23

unknown's avatar
unknown committed
24 25 26 27 28
#ifdef __WIN__
#include <fcntl.h>
#endif
#include <m_ctype.h>

29 30 31
/*
  Old options is used when recreating database, from myisamchk
*/
unknown's avatar
unknown committed
32 33 34 35 36 37 38

int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
	      uint columns, MI_COLUMNDEF *recinfo,
	      uint uniques, MI_UNIQUEDEF *uniquedefs,
	      MI_CREATE_INFO *ci,uint flags)
{
  register uint i,j;
39
  File UNINIT_VAR(dfile),UNINIT_VAR(file);
40
  int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
41
  myf create_flag;
unknown's avatar
unknown committed
42
  uint fields,length,max_key_length,packed,pack_bytes,pointer,real_length_diff,
43
       key_length,info_length,key_segs,options,min_key_length_skip,
44
       base_pos,long_varchar_count,varchar_length,
45
       max_key_block_length,unique_key_parts,fulltext_keys,offset;
unknown's avatar
unknown committed
46
  uint aligned_key_start, block_length, res;
47
  uint internal_table= flags & HA_CREATE_INTERNAL_TABLE;
unknown's avatar
unknown committed
48
  ulong reclength, real_reclength,min_pack_length;
49
  char kfilename[FN_REFLEN],klinkname[FN_REFLEN], *klinkname_ptr= 0;
50
  char dfilename[FN_REFLEN],dlinkname[FN_REFLEN], *dlinkname_ptr= 0;
unknown's avatar
unknown committed
51
  ulong pack_reclength;
unknown's avatar
unknown committed
52
  ulonglong tot_length,max_rows, tmp;
unknown's avatar
unknown committed
53 54 55 56
  enum en_fieldtype type;
  MYISAM_SHARE share;
  MI_KEYDEF *keydef,tmp_keydef;
  MI_UNIQUEDEF *uniquedef;
unknown's avatar
unknown committed
57
  HA_KEYSEG *keyseg,tmp_keyseg;
unknown's avatar
unknown committed
58
  MI_COLUMNDEF *rec;
59
  ulong *rec_per_key_part;
60
  my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
unknown's avatar
unknown committed
61 62
  MI_CREATE_INFO tmp_create_info;
  DBUG_ENTER("mi_create");
63 64
  DBUG_PRINT("enter", ("keys: %u  columns: %u  uniques: %u  flags: %u",
                      keys, columns, uniques, flags));
unknown's avatar
unknown committed
65 66 67 68 69 70 71

  if (!ci)
  {
    bzero((char*) &tmp_create_info,sizeof(tmp_create_info));
    ci=&tmp_create_info;
  }

72
  if (keys + uniques > MI_MAX_KEY || columns == 0)
unknown's avatar
unknown committed
73 74 75
  {
    DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION);
  }
76

unknown's avatar
unknown committed
77 78
  errpos=0;
  options=0;
79
  bzero((uchar*) &share,sizeof(share));
unknown's avatar
unknown committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93

  if (flags & HA_DONT_TOUCH_DATA)
  {
    if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
      options=ci->old_options &
	(HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
	 HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
	 HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
    else
      options=ci->old_options &
	(HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
  }

  if (ci->reloc_rows > ci->max_rows)
94 95 96
    ci->reloc_rows=ci->max_rows;		/* Check if wrong parameter */

  if (!(rec_per_key_part=
97
	(ulong*) my_malloc((keys + uniques)*HA_MAX_KEY_SEG*sizeof(long),
98 99
			   MYF(MY_WME | MY_ZEROFILL))))
    DBUG_RETURN(my_errno);
unknown's avatar
unknown committed
100 101 102

	/* Start by checking fields and field-types used */

103
  reclength=varchar_length=long_varchar_count=packed=
unknown's avatar
unknown committed
104 105 106 107 108 109
    min_pack_length=pack_reclength=0;
  for (rec=recinfo, fields=0 ;
       fields != columns ;
       rec++,fields++)
  {
    reclength+=rec->length;
110 111 112
    if (rec->null_bit)
      options|= HA_OPTION_NULL_FIELDS;

unknown's avatar
unknown committed
113 114 115 116 117 118 119 120 121
    if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
	type != FIELD_CHECK)
    {
      packed++;
      if (type == FIELD_BLOB)
      {
	share.base.blobs++;
	if (pack_reclength != INT_MAX32)
	{
122
	  if (rec->length == 4+portable_sizeof_char_ptr)
unknown's avatar
unknown committed
123 124
	    pack_reclength= INT_MAX32;
	  else
125
	    pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */
unknown's avatar
unknown committed
126 127
	}
      }
unknown's avatar
unknown committed
128 129
      else if (type == FIELD_SKIP_PRESPACE ||
	       type == FIELD_SKIP_ENDSPACE)
unknown's avatar
unknown committed
130 131 132 133 134 135 136
      {
	if (pack_reclength != INT_MAX32)
	  pack_reclength+= rec->length > 255 ? 2 : 1;
	min_pack_length++;
      }
      else if (type == FIELD_VARCHAR)
      {
137
	varchar_length+= rec->length-1;          /* Used for min_pack_length */
unknown's avatar
unknown committed
138
	packed--;
139 140 141
	pack_reclength++;
        min_pack_length++;
        /* We must test for 257 as length includes pack-length */
142
        if (MY_TEST(rec->length >= 257))
143
	{
unknown's avatar
unknown committed
144
	  long_varchar_count++;
145
	  pack_reclength+= 2;			/* May be packed on 3 bytes */
unknown's avatar
unknown committed
146
	}
147
        options|= HA_OPTION_NULL_FIELDS;        /* Use of mi_checksum() */
unknown's avatar
unknown committed
148
      }
unknown's avatar
unknown committed
149
      else if (type != FIELD_SKIP_ZERO)
unknown's avatar
unknown committed
150 151 152 153 154 155 156 157 158 159 160 161 162
      {
	min_pack_length+=rec->length;
	packed--;				/* Not a pack record type */
      }
    }
    else					/* FIELD_NORMAL */
      min_pack_length+=rec->length;
  }
  if ((packed & 7) == 1)
  {				/* Bad packing, try to remove a zero-field */
    while (rec != recinfo)
    {
      rec--;
unknown's avatar
unknown committed
163
      if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
unknown's avatar
unknown committed
164
      {
165 166 167 168
        /*
          NOTE1: here we change a field type FIELD_SKIP_ZERO ->
          FIELD_NORMAL
        */
unknown's avatar
unknown committed
169 170 171 172 173 174 175 176 177 178
	rec->type=(int) FIELD_NORMAL;
	packed--;
	min_pack_length++;
	break;
      }
    }
  }

  if (packed || (flags & HA_PACK_RECORD))
    options|=HA_OPTION_PACK_RECORD;	/* Must use packed records */
179 180 181
  /* We can't use checksum with static length rows */
  if (!(options & HA_OPTION_PACK_RECORD))
    options&= ~HA_OPTION_CHECKSUM;
182 183
  if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
    min_pack_length+= varchar_length;
unknown's avatar
unknown committed
184
  if (flags & HA_CREATE_TMP_TABLE)
185
  {
unknown's avatar
unknown committed
186
    options|= HA_OPTION_TMP_TABLE;
187
    create_mode|= O_NOFOLLOW;
188
  }
unknown's avatar
unknown committed
189 190 191 192 193
  if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
  {
    options|= HA_OPTION_CHECKSUM;
    min_pack_length++;
  }
194 195 196 197 198 199 200
  /*
    Don't set HA_OPTION_NULL_FIELDS if no checksums, as this flag makes
    that file incompatible with MySQL.  This is ok, as this flag is only
    used if one specifics table level checksums.
  */
  if (!(options & HA_OPTION_CHECKSUM))
    options&= ~HA_OPTION_NULL_FIELDS;
unknown's avatar
unknown committed
201 202
  if (flags & HA_CREATE_DELAY_KEY_WRITE)
    options|= HA_OPTION_DELAY_KEY_WRITE;
203 204
  if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
    options|= HA_OPTION_RELIES_ON_SQL_LAYER;
unknown's avatar
unknown committed
205

unknown's avatar
unknown committed
206
  pack_bytes= (packed+7)/8;
unknown's avatar
unknown committed
207 208
  if (pack_reclength != INT_MAX32)
    pack_reclength+= reclength+packed +
209 210
      MY_TEST(test_all_bits(options, HA_OPTION_CHECKSUM |
                                     HA_OPTION_PACK_RECORD));
unknown's avatar
unknown committed
211
  min_pack_length+= pack_bytes;
unknown's avatar
unknown committed
212

213
  if (!ci->data_file_length && ci->max_rows)
unknown's avatar
unknown committed
214
  {
215 216
    if (pack_reclength == INT_MAX32 ||
             (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength)
unknown's avatar
unknown committed
217 218 219 220 221 222 223 224 225 226
      ci->data_file_length= ~(ulonglong) 0;
    else
      ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength;
  }
  else if (!ci->max_rows)
    ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
					 ((options & HA_OPTION_PACK_RECORD) ?
					  3 : 0)));

  if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
unknown's avatar
unknown committed
227
    pointer=mi_get_pointer_length(ci->data_file_length,myisam_data_pointer_size);
unknown's avatar
unknown committed
228
  else
unknown's avatar
unknown committed
229
    pointer=mi_get_pointer_length(ci->max_rows,myisam_data_pointer_size);
unknown's avatar
unknown committed
230 231 232 233 234 235 236 237 238 239 240
  if (!(max_rows=(ulonglong) ci->max_rows))
    max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length);


  real_reclength=reclength;
  if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
  {
    if (reclength <= pointer)
      reclength=pointer+1;		/* reserve place for delete link */
  }
  else
241
    reclength+= long_varchar_count;	/* We need space for varchar! */
unknown's avatar
unknown committed
242 243

  max_key_length=0; tot_length=0 ; key_segs=0;
244
  fulltext_keys=0;
unknown's avatar
unknown committed
245 246 247 248 249 250
  max_key_block_length=0;
  share.state.rec_per_key_part=rec_per_key_part;
  share.state.key_root=key_root;
  share.state.key_del=key_del;
  if (uniques)
  {
unknown's avatar
unknown committed
251
    max_key_block_length= myisam_block_size;
unknown's avatar
unknown committed
252
    max_key_length=	  MI_UNIQUE_HASH_LENGTH + pointer;
unknown's avatar
unknown committed
253 254 255 256 257
  }

  for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
  {

258
    share.state.key_root[i]= HA_OFFSET_ERROR;
259
    min_key_length_skip=length=real_length_diff=0;
unknown's avatar
unknown committed
260
    key_length=pointer;
261 262
    if (keydef->flag & HA_SPATIAL)
    {
263
#ifdef HAVE_SPATIAL
264
      /* BAR TODO to support 3D and more dimensions in the future */
265
      uint sp_segs=SPDIMS*2;
266
      keydef->flag=HA_SPATIAL;
unknown's avatar
unknown committed
267

268 269
      if (flags & HA_DONT_TOUCH_DATA)
      {
270
        /*
271
           called by myisamchk - i.e. table structure was taken from
272
           MYI file and SPATIAL key *does have* additional sp_segs keysegs.
273 274 275
           keydef->seg here points right at the GEOMETRY segment,
           so we only need to decrease keydef->keysegs.
           (see recreate_table() in mi_check.c)
276
        */
277
        keydef->keysegs= 1;
278 279 280 281 282 283
      }

      for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
	   j++, keyseg++)
      {
        if (keyseg->type != HA_KEYTYPE_BINARY &&
284 285
	    keyseg->type != HA_KEYTYPE_VARBINARY1 &&
            keyseg->type != HA_KEYTYPE_VARBINARY2)
286 287
        {
          my_errno=HA_WRONG_CREATE_OPTION;
unknown's avatar
unknown committed
288
          goto err_no_lock;
289 290
        }
      }
291 292
      DBUG_ASSERT(keydef->keysegs == 1);
      keydef->keysegs= sp_segs + 1;
293 294
      key_length+=SPLEN*sp_segs;
      length++;                              /* At least one length byte */
295
      min_key_length_skip+=SPLEN*2*SPDIMS;
296 297
#else
      my_errno= HA_ERR_UNSUPPORTED;
unknown's avatar
unknown committed
298
      goto err_no_lock;
299
#endif /*HAVE_SPATIAL*/
300
    }
301
    else if (keydef->flag & HA_FULLTEXT)
unknown's avatar
unknown committed
302 303 304 305 306 307 308 309
    {
      keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
      options|=HA_OPTION_PACK_KEYS;             /* Using packed keys */

      for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
	   j++, keyseg++)
      {
        if (keyseg->type != HA_KEYTYPE_TEXT &&
310 311
	    keyseg->type != HA_KEYTYPE_VARTEXT1 &&
            keyseg->type != HA_KEYTYPE_VARTEXT2)
unknown's avatar
unknown committed
312 313
        {
          my_errno=HA_WRONG_CREATE_OPTION;
unknown's avatar
unknown committed
314
          goto err_no_lock;
unknown's avatar
unknown committed
315
        }
316 317 318 319 320 321 322 323 324 325
        if (!(keyseg->flag & HA_BLOB_PART) &&
	    (keyseg->type == HA_KEYTYPE_VARTEXT1 ||
             keyseg->type == HA_KEYTYPE_VARTEXT2))
        {
          /* Make a flag that this is a VARCHAR */
          keyseg->flag|= HA_VAR_LENGTH_PART;
          /* Store in bit_start number of bytes used to pack the length */
          keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)?
                              1 : 2);
        }
unknown's avatar
unknown committed
326 327
      }

328
      fulltext_keys++;
329
      key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN;
unknown's avatar
unknown committed
330
      length++;                              /* At least one length byte */
331
      min_key_length_skip+=HA_FT_MAXBYTELEN;
332
      real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT;
unknown's avatar
unknown committed
333 334 335
    }
    else
    {
336 337
      /* Test if prefix compression */
      if (keydef->flag & HA_PACK_KEY)
unknown's avatar
unknown committed
338
      {
339 340 341 342 343
	/* Can't use space_compression on number keys */
	if ((keydef->seg[0].flag & HA_SPACE_PACK) &&
	    keydef->seg[0].type == (int) HA_KEYTYPE_NUM)
	  keydef->seg[0].flag&= ~HA_SPACE_PACK;

unknown's avatar
unknown committed
344
	/* Only use HA_PACK_KEY when first segment is a variable length key */
345
	if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
346
				     HA_VAR_LENGTH_PART)))
347 348 349 350 351 352 353 354 355 356 357
	{
	  /* pack relative to previous key */
	  keydef->flag&= ~HA_PACK_KEY;
	  keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
	}
	else
	{
	  keydef->seg[0].flag|=HA_PACK_KEY;	/* for easyer intern test */
	  keydef->flag|=HA_VAR_LENGTH_KEY;
	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
	}
unknown's avatar
unknown committed
358
      }
359
      if (keydef->flag & HA_BINARY_PACK_KEY)
unknown's avatar
unknown committed
360 361
	options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */

362
      if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
363 364
	share.base.auto_key=i+1;
      for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
unknown's avatar
unknown committed
365
      {
366 367 368 369 370 371 372 373 374 375 376 377 378 379
	/* numbers are stored with high by first to make compression easier */
	switch (keyseg->type) {
	case HA_KEYTYPE_SHORT_INT:
	case HA_KEYTYPE_LONG_INT:
	case HA_KEYTYPE_FLOAT:
	case HA_KEYTYPE_DOUBLE:
	case HA_KEYTYPE_USHORT_INT:
	case HA_KEYTYPE_ULONG_INT:
	case HA_KEYTYPE_LONGLONG:
	case HA_KEYTYPE_ULONGLONG:
	case HA_KEYTYPE_INT24:
	case HA_KEYTYPE_UINT24:
	case HA_KEYTYPE_INT8:
	  keyseg->flag|= HA_SWAP_KEY;
380
          break;
381 382 383 384
        case HA_KEYTYPE_VARTEXT1:
        case HA_KEYTYPE_VARTEXT2:
        case HA_KEYTYPE_VARBINARY1:
        case HA_KEYTYPE_VARBINARY2:
385
          if (!(keyseg->flag & HA_BLOB_PART))
386 387
          {
            /* Make a flag that this is a VARCHAR */
388
            keyseg->flag|= HA_VAR_LENGTH_PART;
389 390 391 392 393
            /* Store in bit_start number of bytes used to pack the length */
            keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
                                 keyseg->type == HA_KEYTYPE_VARBINARY1) ?
                                1 : 2);
          }
394
          break;
395 396
	default:
	  break;
unknown's avatar
unknown committed
397
	}
398 399
	if (keyseg->flag & HA_SPACE_PACK)
	{
400
          DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART));
401 402 403
	  keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
	  length++;				/* At least one length byte */
404
	  min_key_length_skip+=keyseg->length;
405 406
	  if (keyseg->length >= 255)
	  {					/* prefix may be 3 bytes */
407
	    min_key_length_skip+=2;
408 409 410
	    length+=2;
	  }
	}
411
	if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
412
	{
413 414
          DBUG_ASSERT(!test_all_bits(keyseg->flag,
                                    (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
415 416 417
	  keydef->flag|=HA_VAR_LENGTH_KEY;
	  length++;				/* At least one length byte */
	  options|=HA_OPTION_PACK_KEYS;		/* Using packed keys */
418
	  min_key_length_skip+=keyseg->length;
419 420
	  if (keyseg->length >= 255)
	  {					/* prefix may be 3 bytes */
421
	    min_key_length_skip+=2;
422 423 424 425 426 427 428 429 430 431
	    length+=2;
	  }
	}
	key_length+= keyseg->length;
	if (keyseg->null_bit)
	{
	  key_length++;
	  options|=HA_OPTION_PACK_KEYS;
	  keyseg->flag|=HA_NULL_PART;
	  keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
unknown's avatar
unknown committed
432 433 434 435
	}
      }
    } /* if HA_FULLTEXT */
    key_segs+=keydef->keysegs;
436
    if (keydef->keysegs > HA_MAX_KEY_SEG)
unknown's avatar
unknown committed
437 438
    {
      my_errno=HA_WRONG_CREATE_OPTION;
unknown's avatar
unknown committed
439
      goto err_no_lock;
unknown's avatar
unknown committed
440
    }
441 442 443 444 445 446 447
    /*
      key_segs may be 0 in the case when we only want to be able to
      add on row into the table. This can happen with some DISTINCT queries
      in MySQL
    */
    if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
	key_segs)
unknown's avatar
unknown committed
448 449
      share.state.rec_per_key_part[key_segs-1]=1L;
    length+=key_length;
450
    /* Get block length for key, if defined by user */
unknown's avatar
unknown committed
451
    block_length= (keydef->block_length ?
452 453
                   my_round_up_to_next_power(keydef->block_length) :
                   myisam_block_size);
454 455
    block_length= MY_MAX(block_length, MI_MIN_KEY_BLOCK_LENGTH);
    block_length= MY_MIN(block_length, MI_MAX_KEY_BLOCK_LENGTH);
456

457
    keydef->block_length= (uint16) MI_BLOCK_SIZE(length-real_length_diff,
unknown's avatar
unknown committed
458 459
                                                 pointer,MI_MAX_KEYPTR_SIZE,
                                                 block_length);
unknown's avatar
unknown committed
460
    if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
461
        length >= HA_MAX_KEY_BUFF)
unknown's avatar
unknown committed
462 463
    {
      my_errno=HA_WRONG_CREATE_OPTION;
unknown's avatar
unknown committed
464
      goto err_no_lock;
unknown's avatar
unknown committed
465 466 467
    }
    set_if_bigger(max_key_block_length,keydef->block_length);
    keydef->keylength= (uint16) key_length;
468
    keydef->minlength= (uint16) (length-min_key_length_skip);
unknown's avatar
unknown committed
469 470 471 472 473 474 475 476
    keydef->maxlength= (uint16) length;

    if (length > max_key_length)
      max_key_length= length;
    tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
				    (length*2)))*
      (ulong) keydef->block_length;
  }
unknown's avatar
unknown committed
477
  for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
unknown's avatar
unknown committed
478 479 480 481 482 483 484 485
    key_del[i]=HA_OFFSET_ERROR;

  unique_key_parts=0;
  for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
  {
    uniquedef->key=keys+i;
    unique_key_parts+=uniquedef->keysegs;
    share.state.key_root[keys+i]= HA_OFFSET_ERROR;
486 487 488
    tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
                         ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
                         (ulong) myisam_block_size;
unknown's avatar
unknown committed
489 490 491 492 493
  }
  keys+=uniques;				/* Each unique has 1 key */
  key_segs+=uniques;				/* Each unique has 1 key seg */

  base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
unknown's avatar
unknown committed
494 495
	    max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
	    MI_STATE_KEYBLOCK_SIZE+
unknown's avatar
unknown committed
496 497 498 499
	    key_segs*MI_STATE_KEYSEG_SIZE);
  info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
			       keys * MI_KEYDEF_SIZE+
			       uniques * MI_UNIQUEDEF_SIZE +
unknown's avatar
unknown committed
500
			       (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
unknown's avatar
unknown committed
501
			       columns*MI_COLUMNDEF_SIZE);
502 503 504 505
  DBUG_PRINT("info", ("info_length: %u", info_length));
  /* There are only 16 bits for the total header length. */
  if (info_length > 65535)
  {
506 507
    my_printf_error(HA_WRONG_CREATE_OPTION,
                    "MyISAM table '%s' has too many columns and/or "
508 509 510
                    "indexes and/or unique constraints.",
                    MYF(0), name + dirname_length(name));
    my_errno= HA_WRONG_CREATE_OPTION;
unknown's avatar
unknown committed
511
    goto err_no_lock;
512
  }
unknown's avatar
unknown committed
513

514
  bmove(share.state.header.file_version,(uchar*) myisam_file_magic,4);
unknown's avatar
unknown committed
515 516 517 518 519 520 521 522 523
  ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
			HA_OPTION_COMPRESS_RECORD |
			HA_OPTION_TEMP_COMPRESS_RECORD: 0);
  mi_int2store(share.state.header.options,ci->old_options);
  mi_int2store(share.state.header.header_length,info_length);
  mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
  mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
  mi_int2store(share.state.header.base_pos,base_pos);
  share.state.header.language= (ci->language ?
524
				ci->language : default_charset_info->number);
525
  share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
unknown's avatar
unknown committed
526 527 528 529

  share.state.dellink = HA_OFFSET_ERROR;
  share.state.process=	(ulong) getpid();
  share.state.unique=	(ulong) 0;
530
  share.state.update_count=(ulong) 0;
unknown's avatar
unknown committed
531 532 533 534 535
  share.state.version=	(ulong) time((time_t*) 0);
  share.state.sortkey=  (ushort) ~0;
  share.state.auto_increment=ci->auto_increment;
  share.options=options;
  share.base.rec_reflength=pointer;
unknown's avatar
unknown committed
536 537 538 539 540 541 542
  /* Get estimate for index file length (this may be wrong for FT keys) */
  tmp= (tot_length + max_key_block_length * keys *
	MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
  /*
    use maximum of key_file_length we calculated and key_file_length value we
    got from MYI file header (see also myisampack.c:save_state)
  */
unknown's avatar
unknown committed
543
  share.base.key_reflength=
544
    mi_get_pointer_length(MY_MAX(ci->key_file_length,tmp),3);
545
  share.base.keys= share.state.header.keys= keys;
unknown's avatar
unknown committed
546
  share.state.header.uniques= uniques;
547
  share.state.header.fulltext_keys= fulltext_keys;
unknown's avatar
unknown committed
548 549 550
  mi_int2store(share.state.header.key_parts,key_segs);
  mi_int2store(share.state.header.unique_key_parts,unique_key_parts);

551
  mi_set_all_keys_active(share.state.key_map, keys);
552 553 554 555 556 557
  aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
                                               max_key_block_length :
                                               myisam_block_size);

  share.base.keystart= share.state.state.key_file_length=
    MY_ALIGN(info_length, aligned_key_start);
unknown's avatar
unknown committed
558 559 560 561 562
  share.base.max_key_block_length=max_key_block_length;
  share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
  share.base.records=ci->max_rows;
  share.base.reloc=  ci->reloc_rows;
  share.base.reclength=real_reclength;
563
  share.base.pack_reclength= reclength + MY_TEST(options & HA_OPTION_CHECKSUM);
unknown's avatar
unknown committed
564 565
  share.base.max_pack_length=pack_reclength;
  share.base.min_pack_length=min_pack_length;
unknown's avatar
unknown committed
566
  share.base.pack_bits= pack_bytes;
unknown's avatar
unknown committed
567 568 569 570 571 572 573 574 575 576
  share.base.fields=fields;
  share.base.pack_fields=packed;

  /* max_data_file_length and max_key_file_length are recalculated on open */
  if (options & HA_OPTION_TMP_TABLE)
    share.base.max_data_file_length=(my_off_t) ci->data_file_length;

  share.base.min_block_length=
    (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
     ! share.base.blobs) ?
577
    MY_MAX(share.base.pack_reclength,MI_MIN_BLOCK_LENGTH) :
unknown's avatar
unknown committed
578 579
    MI_EXTEND_BLOCK_LENGTH;
  if (! (flags & HA_DONT_TOUCH_DATA))
580
    share.state.create_time= time((time_t*) 0);
unknown's avatar
unknown committed
581

582 583
  if (!internal_table)
    mysql_mutex_lock(&THR_LOCK_myisam);
unknown's avatar
unknown committed
584

585 586 587 588
  /*
    NOTE: For test_if_reopen() we need a real path name. Hence we need
    MY_RETURN_REAL_PATH for every fn_format(filename, ...).
  */
589 590
  if (ci->index_file_name)
  {
591 592
    char *iext= strrchr(ci->index_file_name, '.');
    int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
unknown's avatar
unknown committed
593 594 595 596 597 598
    if (options & HA_OPTION_TMP_TABLE)
    {
      char *path;
      /* chop off the table name, tempory tables use generated name */
      if ((path= strrchr(ci->index_file_name, FN_LIBCHAR)))
        *path= '\0';
599
      fn_format(kfilename, name, ci->index_file_name, MI_NAME_IEXT,
600 601
                MY_REPLACE_DIR | MY_UNPACK_FILENAME |
                MY_RETURN_REAL_PATH | MY_APPEND_EXT);
unknown's avatar
unknown committed
602 603
    }
    else
604
    {
605
      fn_format(kfilename, ci->index_file_name, "", MI_NAME_IEXT,
606 607
                MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
                (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
608
    }
609
    fn_format(klinkname, name, "", MI_NAME_IEXT,
610
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
611
    klinkname_ptr= klinkname;
612 613
    /*
      Don't create the table if the link or file exists to ensure that one
614
      doesn't accidentally destroy another table.
615 616 617 618 619
    */
    create_flag=0;
  }
  else
  {
620 621
    char *iext= strrchr(name, '.');
    int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
622
    fn_format(kfilename, name, "", MI_NAME_IEXT,
623
              MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
624
              (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
625
    /* Replace the current file */
626
    create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
627
  }
unknown's avatar
unknown committed
628

629 630 631 632 633 634
  /*
    If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
    but no entry is made in the table cache for them.
    A TRUNCATE command checks for the table in the cache only and could
    be fooled to believe, the table is not open.
    Pull the emergency brake in this situation. (Bug #8306)
635 636 637

    NOTE: The filename is compared against unique_file_name of every
    open table. Hence we need a real path here.
638
  */
639
  if (!internal_table && test_if_reopen(kfilename))
640
  {
641
    my_printf_error(HA_ERR_TABLE_EXIST, "MyISAM table '%s' is in use "
642 643
                    "(most likely by a MERGE table). Try FLUSH TABLES.",
                    MYF(0), name + dirname_length(name));
644
    my_errno= HA_ERR_TABLE_EXIST;
645 646 647
    goto err;
  }

Marc Alff's avatar
Marc Alff committed
648
  if ((file= mysql_file_create_with_symlink(mi_key_file_kfile,
649
                                            klinkname_ptr, kfilename, 0,
Marc Alff's avatar
Marc Alff committed
650 651
                                            create_mode,
                                            MYF(MY_WME | create_flag))) < 0)
unknown's avatar
unknown committed
652 653
    goto err;
  errpos=1;
unknown's avatar
unknown committed
654

unknown's avatar
unknown committed
655 656
  if (!(flags & HA_DONT_TOUCH_DATA))
  {
unknown's avatar
unknown committed
657
    {
658 659
      if (ci->data_file_name)
      {
660 661 662
        char *dext= strrchr(ci->data_file_name, '.');
        int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);

unknown's avatar
unknown committed
663 664 665 666 667 668
        if (options & HA_OPTION_TMP_TABLE)
        {
          char *path;
          /* chop off the table name, tempory tables use generated name */
          if ((path= strrchr(ci->data_file_name, FN_LIBCHAR)))
            *path= '\0';
669
          fn_format(dfilename, name, ci->data_file_name, MI_NAME_DEXT,
unknown's avatar
unknown committed
670
                    MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
unknown's avatar
unknown committed
671 672
        }
        else
673
        {
674
          fn_format(dfilename, ci->data_file_name, "", MI_NAME_DEXT,
675 676 677 678
                    MY_UNPACK_FILENAME |
                    (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
        }

679
	fn_format(dlinkname, name, "",MI_NAME_DEXT,
680
	          MY_UNPACK_FILENAME | MY_APPEND_EXT);
681
	dlinkname_ptr= dlinkname;
682 683 684 685
	create_flag=0;
      }
      else
      {
686
	fn_format(dfilename,name,"", MI_NAME_DEXT,
687
	          MY_UNPACK_FILENAME | MY_APPEND_EXT);
688
	dlinkname_ptr= 0;
689
        create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
690
      }
691
      if ((dfile=
Marc Alff's avatar
Marc Alff committed
692
           mysql_file_create_with_symlink(mi_key_file_dfile,
693
                                          dlinkname_ptr, dfilename, 0,
Marc Alff's avatar
Marc Alff committed
694 695
                                          create_mode,
                                          MYF(MY_WME | create_flag))) < 0)
unknown's avatar
unknown committed
696 697
	goto err;
    }
unknown's avatar
unknown committed
698 699 700
    errpos=3;
  }

701
  DBUG_PRINT("info", ("write state info and base info"));
unknown's avatar
unknown committed
702 703 704 705
  if (mi_state_info_write(file, &share.state, 2) ||
      mi_base_info_write(file, &share.base))
    goto err;
#ifndef DBUG_OFF
Marc Alff's avatar
Marc Alff committed
706
  if ((uint) mysql_file_tell(file, MYF(0)) != base_pos + MI_BASE_INFO_SIZE)
unknown's avatar
unknown committed
707
  {
Marc Alff's avatar
Marc Alff committed
708
    uint pos=(uint) mysql_file_tell(file, MYF(0));
unknown's avatar
unknown committed
709 710 711 712 713 714
    DBUG_PRINT("warning",("base_length: %d  != used_length: %d",
			  base_pos+ MI_BASE_INFO_SIZE, pos));
  }
#endif

  /* Write key and keyseg definitions */
715
  DBUG_PRINT("info", ("write key and keyseg definitions"));
unknown's avatar
unknown committed
716 717
  for (i=0 ; i < share.base.keys - uniques; i++)
  {
718
    uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
unknown's avatar
unknown committed
719 720 721

    if (mi_keydef_write(file, &keydefs[i]))
      goto err;
722
    for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
unknown's avatar
unknown committed
723
      if (mi_keyseg_write(file, &keydefs[i].seg[j]))
724
       goto err;
725
#ifdef HAVE_SPATIAL
726 727
    for (j=0 ; j < sp_segs ; j++)
    {
unknown's avatar
unknown committed
728
      HA_KEYSEG sseg;
729
      sseg.type=SPTYPE;
730
      sseg.language= 7;                         /* Binary */
731 732
      sseg.null_bit=0;
      sseg.bit_start=0;
733 734
      sseg.bit_length= 0;
      sseg.bit_pos= 0;
735 736 737 738 739 740 741
      sseg.length=SPLEN;
      sseg.null_pos=0;
      sseg.start=j*SPLEN;
      sseg.flag= HA_SWAP_KEY;
      if (mi_keyseg_write(file, &sseg))
        goto err;
    }
742
#endif
unknown's avatar
unknown committed
743 744
  }
  /* Create extra keys for unique definitions */
Michael Widenius's avatar
Michael Widenius committed
745
  offset= real_reclength - uniques * MI_UNIQUE_HASH_LENGTH;
unknown's avatar
unknown committed
746 747 748 749 750 751
  bzero((char*) &tmp_keydef,sizeof(tmp_keydef));
  bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg));
  for (i=0; i < uniques ; i++)
  {
    tmp_keydef.keysegs=1;
    tmp_keydef.flag=		HA_UNIQUE_CHECK;
752
    tmp_keydef.block_length=	(uint16)myisam_block_size;
unknown's avatar
unknown committed
753 754
    tmp_keydef.keylength=	MI_UNIQUE_HASH_LENGTH + pointer;
    tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
755 756
    tmp_keyseg.type=		MI_UNIQUE_HASH_TYPE;
    tmp_keyseg.length=		MI_UNIQUE_HASH_LENGTH;
unknown's avatar
unknown committed
757 758 759 760 761 762 763 764
    tmp_keyseg.start=		offset;
    offset+=			MI_UNIQUE_HASH_LENGTH;
    if (mi_keydef_write(file,&tmp_keydef) ||
	mi_keyseg_write(file,(&tmp_keyseg)))
      goto err;
  }

  /* Save unique definition */
765
  DBUG_PRINT("info", ("write unique definitions"));
unknown's avatar
unknown committed
766 767
  for (i=0 ; i < share.state.header.uniques ; i++)
  {
768 769
    HA_KEYSEG *keyseg_end;
    keyseg= uniquedefs[i].seg;
unknown's avatar
unknown committed
770 771
    if (mi_uniquedef_write(file, &uniquedefs[i]))
      goto err;
772 773 774
    for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
         keyseg < keyseg_end;
         keyseg++)
unknown's avatar
unknown committed
775
    {
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
      switch (keyseg->type) {
      case HA_KEYTYPE_VARTEXT1:
      case HA_KEYTYPE_VARTEXT2:
      case HA_KEYTYPE_VARBINARY1:
      case HA_KEYTYPE_VARBINARY2:
        if (!(keyseg->flag & HA_BLOB_PART))
        {
          keyseg->flag|= HA_VAR_LENGTH_PART;
          keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
                               keyseg->type == HA_KEYTYPE_VARBINARY1) ?
                              1 : 2);
        }
        break;
      default:
        break;
      }
      if (mi_keyseg_write(file, keyseg))
unknown's avatar
unknown committed
793 794 795
	goto err;
    }
  }
796
  DBUG_PRINT("info", ("write field definitions"));
unknown's avatar
unknown committed
797 798 799 800 801
  for (i=0 ; i < share.base.fields ; i++)
    if (mi_recinfo_write(file, &recinfo[i]))
      goto err;

#ifndef DBUG_OFF
Marc Alff's avatar
Marc Alff committed
802
  if ((uint) mysql_file_tell(file, MYF(0)) != info_length)
unknown's avatar
unknown committed
803
  {
Marc Alff's avatar
Marc Alff committed
804
    uint pos= (uint) mysql_file_tell(file, MYF(0));
unknown's avatar
unknown committed
805 806 807 808 809 810
    DBUG_PRINT("warning",("info_length: %d  != used_length: %d",
			  info_length, pos));
  }
#endif

	/* Enlarge files */
811
  DBUG_PRINT("info", ("enlarge to keystart: %lu", (ulong) share.base.keystart));
Marc Alff's avatar
Marc Alff committed
812
  if (mysql_file_chsize(file, (ulong) share.base.keystart, 0, MYF(0)))
unknown's avatar
unknown committed
813 814 815 816 817
    goto err;

  if (! (flags & HA_DONT_TOUCH_DATA))
  {
#ifdef USE_RELOC
Marc Alff's avatar
Marc Alff committed
818 819
    if (mysql_file_chsize(dfile, share.base.min_pack_length*ci->reloc_rows,
                          0, MYF(0)))
unknown's avatar
unknown committed
820 821 822
      goto err;
#endif
    errpos=2;
Marc Alff's avatar
Marc Alff committed
823
    if (mysql_file_close(dfile, MYF(0)))
unknown's avatar
unknown committed
824 825 826
      goto err;
  }
  errpos=0;
827 828
  if (!internal_table)
    mysql_mutex_unlock(&THR_LOCK_myisam);
unknown's avatar
unknown committed
829
  res= 0;
Marc Alff's avatar
Marc Alff committed
830
  if (mysql_file_close(file, MYF(0)))
unknown's avatar
unknown committed
831
    res= my_errno;
832
  my_free(rec_per_key_part);
unknown's avatar
unknown committed
833
  DBUG_RETURN(res);
unknown's avatar
unknown committed
834 835

err:
836 837
  if (!internal_table)
    mysql_mutex_unlock(&THR_LOCK_myisam);
unknown's avatar
unknown committed
838

839
err_no_lock:
unknown's avatar
unknown committed
840 841 842
  save_errno=my_errno;
  switch (errpos) {
  case 3:
Marc Alff's avatar
Marc Alff committed
843
    (void) mysql_file_close(dfile, MYF(0));
unknown's avatar
unknown committed
844 845
    /* fall through */
  case 2:
846 847 848 849 850 851
    if (! (flags & HA_DONT_TOUCH_DATA))
    {
      mysql_file_delete(mi_key_file_dfile, dfilename, MYF(0));
      if (dlinkname_ptr)
        mysql_file_delete(mi_key_file_dfile, dlinkname_ptr, MYF(0));
    }
unknown's avatar
unknown committed
852 853
    /* fall through */
  case 1:
Marc Alff's avatar
Marc Alff committed
854
    (void) mysql_file_close(file, MYF(0));
unknown's avatar
unknown committed
855
    if (! (flags & HA_DONT_TOUCH_DATA))
856 857 858 859 860
    {
      mysql_file_delete(mi_key_file_kfile, kfilename, MYF(0));
      if (klinkname_ptr)
        mysql_file_delete(mi_key_file_kfile, klinkname_ptr, MYF(0));
    }
unknown's avatar
unknown committed
861
  }
862
  my_free(rec_per_key_part);
unknown's avatar
unknown committed
863 864 865 866 867 868
  DBUG_RETURN(my_errno=save_errno);		/* return the fatal errno */
}


uint mi_get_pointer_length(ulonglong file_length, uint def)
{
869
  DBUG_ASSERT(def >= 2 && def <= 7);
unknown's avatar
unknown committed
870 871
  if (file_length)				/* If not default */
  {
872
#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
873
    if (file_length >= 1ULL << 56)
unknown's avatar
unknown committed
874
      def=8;
875
    else
876
#endif
877
    if (file_length >= 1ULL << 48)
unknown's avatar
unknown committed
878
      def=7;
879
    else if (file_length >= 1ULL << 40)
unknown's avatar
unknown committed
880
      def=6;
881
    else if (file_length >= 1ULL << 32)
unknown's avatar
unknown committed
882
      def=5;
883
    else if (file_length >= 1ULL << 24)
unknown's avatar
unknown committed
884
      def=4;
885
    else if (file_length >= 1ULL << 16)
unknown's avatar
unknown committed
886 887 888 889 890 891
      def=3;
    else
      def=2;
  }
  return def;
}