~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/myisam/mi_create.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
Import upstream version 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/* Create a MyISAM table */
 
17
 
 
18
#include "ftdefs.h"
 
19
#include "sp_defs.h"
 
20
#include <my_bit.h>
 
21
 
 
22
#if defined(MSDOS) || defined(__WIN__)
 
23
#ifdef __WIN__
 
24
#include <fcntl.h>
 
25
#else
 
26
#include <process.h>                    /* Prototype for getpid */
 
27
#endif
 
28
#endif
 
29
#include <m_ctype.h>
 
30
 
 
31
/*
 
32
  Old options is used when recreating database, from myisamchk
 
33
*/
 
34
 
 
35
int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
 
36
              uint columns, MI_COLUMNDEF *recinfo,
 
37
              uint uniques, MI_UNIQUEDEF *uniquedefs,
 
38
              MI_CREATE_INFO *ci,uint flags)
 
39
{
 
40
  register uint i,j;
 
41
  File UNINIT_VAR(dfile),file;
 
42
  int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
 
43
  myf create_flag;
 
44
  uint fields,length,max_key_length,packed,pointer,real_length_diff,
 
45
       key_length,info_length,key_segs,options,min_key_length_skip,
 
46
       base_pos,long_varchar_count,varchar_length,
 
47
       max_key_block_length,unique_key_parts,fulltext_keys,offset;
 
48
  uint aligned_key_start, block_length;
 
49
  ulong reclength, real_reclength,min_pack_length;
 
50
  char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
 
51
  ulong pack_reclength;
 
52
  ulonglong tot_length,max_rows, tmp;
 
53
  enum en_fieldtype type;
 
54
  MYISAM_SHARE share;
 
55
  MI_KEYDEF *keydef,tmp_keydef;
 
56
  MI_UNIQUEDEF *uniquedef;
 
57
  HA_KEYSEG *keyseg,tmp_keyseg;
 
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];
 
61
  MI_CREATE_INFO tmp_create_info;
 
62
  DBUG_ENTER("mi_create");
 
63
  DBUG_PRINT("enter", ("keys: %u  columns: %u  uniques: %u  flags: %u",
 
64
                      keys, columns, uniques, flags));
 
65
 
 
66
  if (!ci)
 
67
  {
 
68
    bzero((char*) &tmp_create_info,sizeof(tmp_create_info));
 
69
    ci=&tmp_create_info;
 
70
  }
 
71
 
 
72
  if (keys + uniques > MI_MAX_KEY || columns == 0)
 
73
  {
 
74
    DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION);
 
75
  }
 
76
  LINT_INIT(dfile);
 
77
  LINT_INIT(file);
 
78
  errpos=0;
 
79
  options=0;
 
80
  bzero((uchar*) &share,sizeof(share));
 
81
 
 
82
  if (flags & HA_DONT_TOUCH_DATA)
 
83
  {
 
84
    if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
 
85
      options=ci->old_options &
 
86
        (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
 
87
         HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
 
88
         HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
 
89
    else
 
90
      options=ci->old_options &
 
91
        (HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE);
 
92
  }
 
93
 
 
94
  if (ci->reloc_rows > ci->max_rows)
 
95
    ci->reloc_rows=ci->max_rows;                /* Check if wrong parameter */
 
96
 
 
97
  if (!(rec_per_key_part=
 
98
        (ulong*) my_malloc((keys + uniques)*MI_MAX_KEY_SEG*sizeof(long),
 
99
                           MYF(MY_WME | MY_ZEROFILL))))
 
100
    DBUG_RETURN(my_errno);
 
101
 
 
102
        /* Start by checking fields and field-types used */
 
103
 
 
104
  reclength=varchar_length=long_varchar_count=packed=
 
105
    min_pack_length=pack_reclength=0;
 
106
  for (rec=recinfo, fields=0 ;
 
107
       fields != columns ;
 
108
       rec++,fields++)
 
109
  {
 
110
    reclength+=rec->length;
 
111
    if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
 
112
        type != FIELD_CHECK)
 
113
    {
 
114
      packed++;
 
115
      if (type == FIELD_BLOB)
 
116
      {
 
117
        share.base.blobs++;
 
118
        if (pack_reclength != INT_MAX32)
 
119
        {
 
120
          if (rec->length == 4+portable_sizeof_char_ptr)
 
121
            pack_reclength= INT_MAX32;
 
122
          else
 
123
            pack_reclength+=(1 << ((rec->length-portable_sizeof_char_ptr)*8)); /* Max blob length */
 
124
        }
 
125
      }
 
126
      else if (type == FIELD_SKIP_PRESPACE ||
 
127
               type == FIELD_SKIP_ENDSPACE)
 
128
      {
 
129
        if (pack_reclength != INT_MAX32)
 
130
          pack_reclength+= rec->length > 255 ? 2 : 1;
 
131
        min_pack_length++;
 
132
      }
 
133
      else if (type == FIELD_VARCHAR)
 
134
      {
 
135
        varchar_length+= rec->length-1;          /* Used for min_pack_length */
 
136
        packed--;
 
137
        pack_reclength++;
 
138
        min_pack_length++;
 
139
        /* We must test for 257 as length includes pack-length */
 
140
        if (test(rec->length >= 257))
 
141
        {
 
142
          long_varchar_count++;
 
143
          pack_reclength+= 2;                   /* May be packed on 3 bytes */
 
144
        }
 
145
      }
 
146
      else if (type != FIELD_SKIP_ZERO)
 
147
      {
 
148
        min_pack_length+=rec->length;
 
149
        packed--;                               /* Not a pack record type */
 
150
      }
 
151
    }
 
152
    else                                        /* FIELD_NORMAL */
 
153
      min_pack_length+=rec->length;
 
154
  }
 
155
  if ((packed & 7) == 1)
 
156
  {                             /* Bad packing, try to remove a zero-field */
 
157
    while (rec != recinfo)
 
158
    {
 
159
      rec--;
 
160
      if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1)
 
161
      {
 
162
        /*
 
163
          NOTE1: here we change a field type FIELD_SKIP_ZERO ->
 
164
          FIELD_NORMAL
 
165
        */
 
166
        rec->type=(int) FIELD_NORMAL;
 
167
        packed--;
 
168
        min_pack_length++;
 
169
        break;
 
170
      }
 
171
    }
 
172
  }
 
173
 
 
174
  if (packed || (flags & HA_PACK_RECORD))
 
175
    options|=HA_OPTION_PACK_RECORD;     /* Must use packed records */
 
176
  /* We can't use checksum with static length rows */
 
177
  if (!(options & HA_OPTION_PACK_RECORD))
 
178
    options&= ~HA_OPTION_CHECKSUM;
 
179
  if (!(options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
 
180
    min_pack_length+= varchar_length;
 
181
  if (flags & HA_CREATE_TMP_TABLE)
 
182
  {
 
183
    options|= HA_OPTION_TMP_TABLE;
 
184
    create_mode|= O_EXCL | O_NOFOLLOW;
 
185
  }
 
186
  if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
 
187
  {
 
188
    options|= HA_OPTION_CHECKSUM;
 
189
    min_pack_length++;
 
190
  }
 
191
  if (flags & HA_CREATE_DELAY_KEY_WRITE)
 
192
    options|= HA_OPTION_DELAY_KEY_WRITE;
 
193
  if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
 
194
    options|= HA_OPTION_RELIES_ON_SQL_LAYER;
 
195
 
 
196
  packed=(packed+7)/8;
 
197
  if (pack_reclength != INT_MAX32)
 
198
    pack_reclength+= reclength+packed +
 
199
      test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_OPTION_PACK_RECORD));
 
200
  min_pack_length+=packed;
 
201
 
 
202
  if (!ci->data_file_length && ci->max_rows)
 
203
  {
 
204
    if (pack_reclength == INT_MAX32 ||
 
205
             (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength)
 
206
      ci->data_file_length= ~(ulonglong) 0;
 
207
    else
 
208
      ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength;
 
209
  }
 
210
  else if (!ci->max_rows)
 
211
    ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
 
212
                                         ((options & HA_OPTION_PACK_RECORD) ?
 
213
                                          3 : 0)));
 
214
 
 
215
  if (options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD))
 
216
    pointer=mi_get_pointer_length(ci->data_file_length,myisam_data_pointer_size);
 
217
  else
 
218
    pointer=mi_get_pointer_length(ci->max_rows,myisam_data_pointer_size);
 
219
  if (!(max_rows=(ulonglong) ci->max_rows))
 
220
    max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length);
 
221
 
 
222
 
 
223
  real_reclength=reclength;
 
224
  if (!(options & (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD)))
 
225
  {
 
226
    if (reclength <= pointer)
 
227
      reclength=pointer+1;              /* reserve place for delete link */
 
228
  }
 
229
  else
 
230
    reclength+= long_varchar_count;     /* We need space for varchar! */
 
231
 
 
232
  max_key_length=0; tot_length=0 ; key_segs=0;
 
233
  fulltext_keys=0;
 
234
  max_key_block_length=0;
 
235
  share.state.rec_per_key_part=rec_per_key_part;
 
236
  share.state.key_root=key_root;
 
237
  share.state.key_del=key_del;
 
238
  if (uniques)
 
239
  {
 
240
    max_key_block_length= myisam_block_size;
 
241
    max_key_length=       MI_UNIQUE_HASH_LENGTH + pointer;
 
242
  }
 
243
 
 
244
  for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
 
245
  {
 
246
 
 
247
    share.state.key_root[i]= HA_OFFSET_ERROR;
 
248
    min_key_length_skip=length=real_length_diff=0;
 
249
    key_length=pointer;
 
250
    if (keydef->flag & HA_SPATIAL)
 
251
    {
 
252
#ifdef HAVE_SPATIAL
 
253
      /* BAR TODO to support 3D and more dimensions in the future */
 
254
      uint sp_segs=SPDIMS*2;
 
255
      keydef->flag=HA_SPATIAL;
 
256
 
 
257
      if (flags & HA_DONT_TOUCH_DATA)
 
258
      {
 
259
        /*
 
260
           called by myisamchk - i.e. table structure was taken from
 
261
           MYI file and SPATIAL key *does have* additional sp_segs keysegs.
 
262
           keydef->seg here points right at the GEOMETRY segment,
 
263
           so we only need to decrease keydef->keysegs.
 
264
           (see recreate_table() in mi_check.c)
 
265
        */
 
266
        keydef->keysegs-=sp_segs-1;
 
267
      }
 
268
 
 
269
      for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
 
270
           j++, keyseg++)
 
271
      {
 
272
        if (keyseg->type != HA_KEYTYPE_BINARY &&
 
273
            keyseg->type != HA_KEYTYPE_VARBINARY1 &&
 
274
            keyseg->type != HA_KEYTYPE_VARBINARY2)
 
275
        {
 
276
          my_errno=HA_WRONG_CREATE_OPTION;
 
277
          goto err;
 
278
        }
 
279
      }
 
280
      keydef->keysegs+=sp_segs;
 
281
      key_length+=SPLEN*sp_segs;
 
282
      length++;                              /* At least one length byte */
 
283
      min_key_length_skip+=SPLEN*2*SPDIMS;
 
284
#else
 
285
      my_errno= HA_ERR_UNSUPPORTED;
 
286
      goto err;
 
287
#endif /*HAVE_SPATIAL*/
 
288
    }
 
289
    else if (keydef->flag & HA_FULLTEXT)
 
290
    {
 
291
      keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
 
292
      options|=HA_OPTION_PACK_KEYS;             /* Using packed keys */
 
293
 
 
294
      for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
 
295
           j++, keyseg++)
 
296
      {
 
297
        if (keyseg->type != HA_KEYTYPE_TEXT &&
 
298
            keyseg->type != HA_KEYTYPE_VARTEXT1 &&
 
299
            keyseg->type != HA_KEYTYPE_VARTEXT2)
 
300
        {
 
301
          my_errno=HA_WRONG_CREATE_OPTION;
 
302
          goto err;
 
303
        }
 
304
        if (!(keyseg->flag & HA_BLOB_PART) &&
 
305
            (keyseg->type == HA_KEYTYPE_VARTEXT1 ||
 
306
             keyseg->type == HA_KEYTYPE_VARTEXT2))
 
307
        {
 
308
          /* Make a flag that this is a VARCHAR */
 
309
          keyseg->flag|= HA_VAR_LENGTH_PART;
 
310
          /* Store in bit_start number of bytes used to pack the length */
 
311
          keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)?
 
312
                              1 : 2);
 
313
        }
 
314
      }
 
315
 
 
316
      fulltext_keys++;
 
317
      key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN;
 
318
      length++;                              /* At least one length byte */
 
319
      min_key_length_skip+=HA_FT_MAXBYTELEN;
 
320
      real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT;
 
321
    }
 
322
    else
 
323
    {
 
324
      /* Test if prefix compression */
 
325
      if (keydef->flag & HA_PACK_KEY)
 
326
      {
 
327
        /* Can't use space_compression on number keys */
 
328
        if ((keydef->seg[0].flag & HA_SPACE_PACK) &&
 
329
            keydef->seg[0].type == (int) HA_KEYTYPE_NUM)
 
330
          keydef->seg[0].flag&= ~HA_SPACE_PACK;
 
331
 
 
332
        /* Only use HA_PACK_KEY when first segment is a variable length key */
 
333
        if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
 
334
                                     HA_VAR_LENGTH_PART)))
 
335
        {
 
336
          /* pack relative to previous key */
 
337
          keydef->flag&= ~HA_PACK_KEY;
 
338
          keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
 
339
        }
 
340
        else
 
341
        {
 
342
          keydef->seg[0].flag|=HA_PACK_KEY;     /* for easyer intern test */
 
343
          keydef->flag|=HA_VAR_LENGTH_KEY;
 
344
          options|=HA_OPTION_PACK_KEYS;         /* Using packed keys */
 
345
        }
 
346
      }
 
347
      if (keydef->flag & HA_BINARY_PACK_KEY)
 
348
        options|=HA_OPTION_PACK_KEYS;           /* Using packed keys */
 
349
 
 
350
      if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
 
351
        share.base.auto_key=i+1;
 
352
      for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
 
353
      {
 
354
        /* numbers are stored with high by first to make compression easier */
 
355
        switch (keyseg->type) {
 
356
        case HA_KEYTYPE_SHORT_INT:
 
357
        case HA_KEYTYPE_LONG_INT:
 
358
        case HA_KEYTYPE_FLOAT:
 
359
        case HA_KEYTYPE_DOUBLE:
 
360
        case HA_KEYTYPE_USHORT_INT:
 
361
        case HA_KEYTYPE_ULONG_INT:
 
362
        case HA_KEYTYPE_LONGLONG:
 
363
        case HA_KEYTYPE_ULONGLONG:
 
364
        case HA_KEYTYPE_INT24:
 
365
        case HA_KEYTYPE_UINT24:
 
366
        case HA_KEYTYPE_INT8:
 
367
          keyseg->flag|= HA_SWAP_KEY;
 
368
          break;
 
369
        case HA_KEYTYPE_VARTEXT1:
 
370
        case HA_KEYTYPE_VARTEXT2:
 
371
        case HA_KEYTYPE_VARBINARY1:
 
372
        case HA_KEYTYPE_VARBINARY2:
 
373
          if (!(keyseg->flag & HA_BLOB_PART))
 
374
          {
 
375
            /* Make a flag that this is a VARCHAR */
 
376
            keyseg->flag|= HA_VAR_LENGTH_PART;
 
377
            /* Store in bit_start number of bytes used to pack the length */
 
378
            keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
 
379
                                 keyseg->type == HA_KEYTYPE_VARBINARY1) ?
 
380
                                1 : 2);
 
381
          }
 
382
          break;
 
383
        default:
 
384
          break;
 
385
        }
 
386
        if (keyseg->flag & HA_SPACE_PACK)
 
387
        {
 
388
          DBUG_ASSERT(!(keyseg->flag & HA_VAR_LENGTH_PART));
 
389
          keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
 
390
          options|=HA_OPTION_PACK_KEYS;         /* Using packed keys */
 
391
          length++;                             /* At least one length byte */
 
392
          min_key_length_skip+=keyseg->length;
 
393
          if (keyseg->length >= 255)
 
394
          {                                     /* prefix may be 3 bytes */
 
395
            min_key_length_skip+=2;
 
396
            length+=2;
 
397
          }
 
398
        }
 
399
        if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
400
        {
 
401
          DBUG_ASSERT(!test_all_bits(keyseg->flag,
 
402
                                    (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
 
403
          keydef->flag|=HA_VAR_LENGTH_KEY;
 
404
          length++;                             /* At least one length byte */
 
405
          options|=HA_OPTION_PACK_KEYS;         /* Using packed keys */
 
406
          min_key_length_skip+=keyseg->length;
 
407
          if (keyseg->length >= 255)
 
408
          {                                     /* prefix may be 3 bytes */
 
409
            min_key_length_skip+=2;
 
410
            length+=2;
 
411
          }
 
412
        }
 
413
        key_length+= keyseg->length;
 
414
        if (keyseg->null_bit)
 
415
        {
 
416
          key_length++;
 
417
          options|=HA_OPTION_PACK_KEYS;
 
418
          keyseg->flag|=HA_NULL_PART;
 
419
          keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
 
420
        }
 
421
      }
 
422
    } /* if HA_FULLTEXT */
 
423
    key_segs+=keydef->keysegs;
 
424
    if (keydef->keysegs > MI_MAX_KEY_SEG)
 
425
    {
 
426
      my_errno=HA_WRONG_CREATE_OPTION;
 
427
      goto err;
 
428
    }
 
429
    /*
 
430
      key_segs may be 0 in the case when we only want to be able to
 
431
      add on row into the table. This can happen with some DISTINCT queries
 
432
      in MySQL
 
433
    */
 
434
    if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
 
435
        key_segs)
 
436
      share.state.rec_per_key_part[key_segs-1]=1L;
 
437
    length+=key_length;
 
438
    /* Get block length for key, if defined by user */
 
439
    block_length= (keydef->block_length ? 
 
440
                   my_round_up_to_next_power(keydef->block_length) :
 
441
                   myisam_block_size);
 
442
    block_length= max(block_length, MI_MIN_KEY_BLOCK_LENGTH);
 
443
    block_length= min(block_length, MI_MAX_KEY_BLOCK_LENGTH);
 
444
 
 
445
    keydef->block_length= (uint16) MI_BLOCK_SIZE(length-real_length_diff,
 
446
                                                 pointer,MI_MAX_KEYPTR_SIZE,
 
447
                                                 block_length);
 
448
    if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
 
449
        length >= MI_MAX_KEY_BUFF)
 
450
    {
 
451
      my_errno=HA_WRONG_CREATE_OPTION;
 
452
      goto err;
 
453
    }
 
454
    set_if_bigger(max_key_block_length,keydef->block_length);
 
455
    keydef->keylength= (uint16) key_length;
 
456
    keydef->minlength= (uint16) (length-min_key_length_skip);
 
457
    keydef->maxlength= (uint16) length;
 
458
 
 
459
    if (length > max_key_length)
 
460
      max_key_length= length;
 
461
    tot_length+= (max_rows/(ulong) (((uint) keydef->block_length-5)/
 
462
                                    (length*2)))*
 
463
      (ulong) keydef->block_length;
 
464
  }
 
465
  for (i=max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH ; i-- ; )
 
466
    key_del[i]=HA_OFFSET_ERROR;
 
467
 
 
468
  unique_key_parts=0;
 
469
  offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
 
470
  for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
 
471
  {
 
472
    uniquedef->key=keys+i;
 
473
    unique_key_parts+=uniquedef->keysegs;
 
474
    share.state.key_root[keys+i]= HA_OFFSET_ERROR;
 
475
    tot_length+= (max_rows/(ulong) (((uint) myisam_block_size-5)/
 
476
                         ((MI_UNIQUE_HASH_LENGTH + pointer)*2)))*
 
477
                         (ulong) myisam_block_size;
 
478
  }
 
479
  keys+=uniques;                                /* Each unique has 1 key */
 
480
  key_segs+=uniques;                            /* Each unique has 1 key seg */
 
481
 
 
482
  base_pos=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE +
 
483
            max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH*
 
484
            MI_STATE_KEYBLOCK_SIZE+
 
485
            key_segs*MI_STATE_KEYSEG_SIZE);
 
486
  info_length=base_pos+(uint) (MI_BASE_INFO_SIZE+
 
487
                               keys * MI_KEYDEF_SIZE+
 
488
                               uniques * MI_UNIQUEDEF_SIZE +
 
489
                               (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
 
490
                               columns*MI_COLUMNDEF_SIZE);
 
491
  DBUG_PRINT("info", ("info_length: %u", info_length));
 
492
  /* There are only 16 bits for the total header length. */
 
493
  if (info_length > 65535)
 
494
  {
 
495
    my_printf_error(0, "MyISAM table '%s' has too many columns and/or "
 
496
                    "indexes and/or unique constraints.",
 
497
                    MYF(0), name + dirname_length(name));
 
498
    my_errno= HA_WRONG_CREATE_OPTION;
 
499
    goto err;
 
500
  }
 
501
 
 
502
  bmove(share.state.header.file_version,(uchar*) myisam_file_magic,4);
 
503
  ci->old_options=options| (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
 
504
                        HA_OPTION_COMPRESS_RECORD |
 
505
                        HA_OPTION_TEMP_COMPRESS_RECORD: 0);
 
506
  mi_int2store(share.state.header.options,ci->old_options);
 
507
  mi_int2store(share.state.header.header_length,info_length);
 
508
  mi_int2store(share.state.header.state_info_length,MI_STATE_INFO_SIZE);
 
509
  mi_int2store(share.state.header.base_info_length,MI_BASE_INFO_SIZE);
 
510
  mi_int2store(share.state.header.base_pos,base_pos);
 
511
  share.state.header.language= (ci->language ?
 
512
                                ci->language : default_charset_info->number);
 
513
  share.state.header.max_block_size_index= max_key_block_length/MI_MIN_KEY_BLOCK_LENGTH;
 
514
 
 
515
  share.state.dellink = HA_OFFSET_ERROR;
 
516
  share.state.process=  (ulong) getpid();
 
517
  share.state.unique=   (ulong) 0;
 
518
  share.state.update_count=(ulong) 0;
 
519
  share.state.version=  (ulong) time((time_t*) 0);
 
520
  share.state.sortkey=  (ushort) ~0;
 
521
  share.state.auto_increment=ci->auto_increment;
 
522
  share.options=options;
 
523
  share.base.rec_reflength=pointer;
 
524
  /* Get estimate for index file length (this may be wrong for FT keys) */
 
525
  tmp= (tot_length + max_key_block_length * keys *
 
526
        MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH;
 
527
  /*
 
528
    use maximum of key_file_length we calculated and key_file_length value we
 
529
    got from MYI file header (see also myisampack.c:save_state)
 
530
  */
 
531
  share.base.key_reflength=
 
532
    mi_get_pointer_length(max(ci->key_file_length,tmp),3);
 
533
  share.base.keys= share.state.header.keys= keys;
 
534
  share.state.header.uniques= uniques;
 
535
  share.state.header.fulltext_keys= fulltext_keys;
 
536
  mi_int2store(share.state.header.key_parts,key_segs);
 
537
  mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
 
538
 
 
539
  mi_set_all_keys_active(share.state.key_map, keys);
 
540
  aligned_key_start= my_round_up_to_next_power(max_key_block_length ?
 
541
                                               max_key_block_length :
 
542
                                               myisam_block_size);
 
543
 
 
544
  share.base.keystart= share.state.state.key_file_length=
 
545
    MY_ALIGN(info_length, aligned_key_start);
 
546
  share.base.max_key_block_length=max_key_block_length;
 
547
  share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
 
548
  share.base.records=ci->max_rows;
 
549
  share.base.reloc=  ci->reloc_rows;
 
550
  share.base.reclength=real_reclength;
 
551
  share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);
 
552
  share.base.max_pack_length=pack_reclength;
 
553
  share.base.min_pack_length=min_pack_length;
 
554
  share.base.pack_bits=packed;
 
555
  share.base.fields=fields;
 
556
  share.base.pack_fields=packed;
 
557
#ifdef USE_RAID
 
558
  share.base.raid_type=ci->raid_type;
 
559
  share.base.raid_chunks=ci->raid_chunks;
 
560
  share.base.raid_chunksize=ci->raid_chunksize;
 
561
#endif
 
562
 
 
563
  /* max_data_file_length and max_key_file_length are recalculated on open */
 
564
  if (options & HA_OPTION_TMP_TABLE)
 
565
    share.base.max_data_file_length=(my_off_t) ci->data_file_length;
 
566
 
 
567
  share.base.min_block_length=
 
568
    (share.base.pack_reclength+3 < MI_EXTEND_BLOCK_LENGTH &&
 
569
     ! share.base.blobs) ?
 
570
    max(share.base.pack_reclength,MI_MIN_BLOCK_LENGTH) :
 
571
    MI_EXTEND_BLOCK_LENGTH;
 
572
  if (! (flags & HA_DONT_TOUCH_DATA))
 
573
    share.state.create_time= (long) time((time_t*) 0);
 
574
 
 
575
  pthread_mutex_lock(&THR_LOCK_myisam);
 
576
 
 
577
  /*
 
578
    NOTE: For test_if_reopen() we need a real path name. Hence we need
 
579
    MY_RETURN_REAL_PATH for every fn_format(filename, ...).
 
580
  */
 
581
  if (ci->index_file_name)
 
582
  {
 
583
    char *iext= strrchr(ci->index_file_name, '.');
 
584
    int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
 
585
    if (options & HA_OPTION_TMP_TABLE)
 
586
    {
 
587
      char *path;
 
588
      /* chop off the table name, tempory tables use generated name */
 
589
      if ((path= strrchr(ci->index_file_name, FN_LIBCHAR)))
 
590
        *path= '\0';
 
591
      fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT,
 
592
                MY_REPLACE_DIR | MY_UNPACK_FILENAME |
 
593
                MY_RETURN_REAL_PATH | MY_APPEND_EXT);
 
594
    }
 
595
    else
 
596
    {
 
597
      fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT,
 
598
                MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
 
599
                (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
 
600
    }
 
601
    fn_format(linkname, name, "", MI_NAME_IEXT,
 
602
              MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
603
    linkname_ptr=linkname;
 
604
    /*
 
605
      Don't create the table if the link or file exists to ensure that one
 
606
      doesn't accidently destroy another table.
 
607
    */
 
608
    create_flag=0;
 
609
  }
 
610
  else
 
611
  {
 
612
    char *iext= strrchr(name, '.');
 
613
    int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
 
614
    fn_format(filename, name, "", MI_NAME_IEXT,
 
615
              MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
 
616
              (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
 
617
    linkname_ptr=0;
 
618
    /* Replace the current file */
 
619
    create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
 
620
  }
 
621
 
 
622
  /*
 
623
    If a MRG_MyISAM table is in use, the mapped MyISAM tables are open,
 
624
    but no entry is made in the table cache for them.
 
625
    A TRUNCATE command checks for the table in the cache only and could
 
626
    be fooled to believe, the table is not open.
 
627
    Pull the emergency brake in this situation. (Bug #8306)
 
628
 
 
629
    NOTE: The filename is compared against unique_file_name of every
 
630
    open table. Hence we need a real path here.
 
631
  */
 
632
  if (test_if_reopen(filename))
 
633
  {
 
634
    my_printf_error(0, "MyISAM table '%s' is in use "
 
635
                    "(most likely by a MERGE table). Try FLUSH TABLES.",
 
636
                    MYF(0), name + dirname_length(name));
 
637
    my_errno= HA_ERR_TABLE_EXIST;
 
638
    goto err;
 
639
  }
 
640
 
 
641
  if ((file= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
 
642
                                    MYF(MY_WME | create_flag))) < 0)
 
643
    goto err;
 
644
  errpos=1;
 
645
 
 
646
  if (!(flags & HA_DONT_TOUCH_DATA))
 
647
  {
 
648
#ifdef USE_RAID
 
649
    if (share.base.raid_type)
 
650
    {
 
651
      (void) fn_format(filename, name, "", MI_NAME_DEXT,
 
652
                       MY_UNPACK_FILENAME | MY_APPEND_EXT);
 
653
      if ((dfile=my_raid_create(filename, 0, create_mode,
 
654
                                share.base.raid_type,
 
655
                                share.base.raid_chunks,
 
656
                                share.base.raid_chunksize,
 
657
                                MYF(MY_WME | MY_RAID))) < 0)
 
658
        goto err;
 
659
    }
 
660
    else
 
661
#endif
 
662
    {
 
663
      if (ci->data_file_name)
 
664
      {
 
665
        char *dext= strrchr(ci->data_file_name, '.');
 
666
        int have_dext= dext && !strcmp(dext, MI_NAME_DEXT);
 
667
 
 
668
        if (options & HA_OPTION_TMP_TABLE)
 
669
        {
 
670
          char *path;
 
671
          /* chop off the table name, tempory tables use generated name */
 
672
          if ((path= strrchr(ci->data_file_name, FN_LIBCHAR)))
 
673
            *path= '\0';
 
674
          fn_format(filename, name, ci->data_file_name, MI_NAME_DEXT,
 
675
                    MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
 
676
        }
 
677
        else
 
678
        {
 
679
          fn_format(filename, ci->data_file_name, "", MI_NAME_DEXT,
 
680
                    MY_UNPACK_FILENAME |
 
681
                    (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
 
682
        }
 
683
 
 
684
        fn_format(linkname, name, "",MI_NAME_DEXT,
 
685
                  MY_UNPACK_FILENAME | MY_APPEND_EXT);
 
686
        linkname_ptr=linkname;
 
687
        create_flag=0;
 
688
      }
 
689
      else
 
690
      {
 
691
        fn_format(filename,name,"", MI_NAME_DEXT,
 
692
                  MY_UNPACK_FILENAME | MY_APPEND_EXT);
 
693
        linkname_ptr=0;
 
694
        create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
 
695
      }
 
696
      if ((dfile=
 
697
           my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
 
698
                                  MYF(MY_WME | create_flag))) < 0)
 
699
        goto err;
 
700
    }
 
701
    errpos=3;
 
702
  }
 
703
 
 
704
  DBUG_PRINT("info", ("write state info and base info"));
 
705
  if (mi_state_info_write(file, &share.state, 2) ||
 
706
      mi_base_info_write(file, &share.base))
 
707
    goto err;
 
708
#ifndef DBUG_OFF
 
709
  if ((uint) my_tell(file,MYF(0)) != base_pos+ MI_BASE_INFO_SIZE)
 
710
  {
 
711
    uint pos=(uint) my_tell(file,MYF(0));
 
712
    DBUG_PRINT("warning",("base_length: %d  != used_length: %d",
 
713
                          base_pos+ MI_BASE_INFO_SIZE, pos));
 
714
  }
 
715
#endif
 
716
 
 
717
  /* Write key and keyseg definitions */
 
718
  DBUG_PRINT("info", ("write key and keyseg definitions"));
 
719
  for (i=0 ; i < share.base.keys - uniques; i++)
 
720
  {
 
721
    uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
 
722
 
 
723
    if (mi_keydef_write(file, &keydefs[i]))
 
724
      goto err;
 
725
    for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
 
726
      if (mi_keyseg_write(file, &keydefs[i].seg[j]))
 
727
       goto err;
 
728
#ifdef HAVE_SPATIAL
 
729
    for (j=0 ; j < sp_segs ; j++)
 
730
    {
 
731
      HA_KEYSEG sseg;
 
732
      sseg.type=SPTYPE;
 
733
      sseg.language= 7;                         /* Binary */
 
734
      sseg.null_bit=0;
 
735
      sseg.bit_start=0;
 
736
      sseg.bit_end=0;
 
737
      sseg.bit_length= 0;
 
738
      sseg.bit_pos= 0;
 
739
      sseg.length=SPLEN;
 
740
      sseg.null_pos=0;
 
741
      sseg.start=j*SPLEN;
 
742
      sseg.flag= HA_SWAP_KEY;
 
743
      if (mi_keyseg_write(file, &sseg))
 
744
        goto err;
 
745
    }
 
746
#endif
 
747
  }
 
748
  /* Create extra keys for unique definitions */
 
749
  offset=reclength-uniques*MI_UNIQUE_HASH_LENGTH;
 
750
  bzero((char*) &tmp_keydef,sizeof(tmp_keydef));
 
751
  bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg));
 
752
  for (i=0; i < uniques ; i++)
 
753
  {
 
754
    tmp_keydef.keysegs=1;
 
755
    tmp_keydef.flag=            HA_UNIQUE_CHECK;
 
756
    tmp_keydef.block_length=    (uint16)myisam_block_size;
 
757
    tmp_keydef.keylength=       MI_UNIQUE_HASH_LENGTH + pointer;
 
758
    tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
 
759
    tmp_keyseg.type=            MI_UNIQUE_HASH_TYPE;
 
760
    tmp_keyseg.length=          MI_UNIQUE_HASH_LENGTH;
 
761
    tmp_keyseg.start=           offset;
 
762
    offset+=                    MI_UNIQUE_HASH_LENGTH;
 
763
    if (mi_keydef_write(file,&tmp_keydef) ||
 
764
        mi_keyseg_write(file,(&tmp_keyseg)))
 
765
      goto err;
 
766
  }
 
767
 
 
768
  /* Save unique definition */
 
769
  DBUG_PRINT("info", ("write unique definitions"));
 
770
  for (i=0 ; i < share.state.header.uniques ; i++)
 
771
  {
 
772
    HA_KEYSEG *keyseg_end;
 
773
    keyseg= uniquedefs[i].seg;
 
774
    if (mi_uniquedef_write(file, &uniquedefs[i]))
 
775
      goto err;
 
776
    for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
 
777
         keyseg < keyseg_end;
 
778
         keyseg++)
 
779
    {
 
780
      switch (keyseg->type) {
 
781
      case HA_KEYTYPE_VARTEXT1:
 
782
      case HA_KEYTYPE_VARTEXT2:
 
783
      case HA_KEYTYPE_VARBINARY1:
 
784
      case HA_KEYTYPE_VARBINARY2:
 
785
        if (!(keyseg->flag & HA_BLOB_PART))
 
786
        {
 
787
          keyseg->flag|= HA_VAR_LENGTH_PART;
 
788
          keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
 
789
                               keyseg->type == HA_KEYTYPE_VARBINARY1) ?
 
790
                              1 : 2);
 
791
        }
 
792
        break;
 
793
      default:
 
794
        break;
 
795
      }
 
796
      if (mi_keyseg_write(file, keyseg))
 
797
        goto err;
 
798
    }
 
799
  }
 
800
  DBUG_PRINT("info", ("write field definitions"));
 
801
  for (i=0 ; i < share.base.fields ; i++)
 
802
    if (mi_recinfo_write(file, &recinfo[i]))
 
803
      goto err;
 
804
 
 
805
#ifndef DBUG_OFF
 
806
  if ((uint) my_tell(file,MYF(0)) != info_length)
 
807
  {
 
808
    uint pos= (uint) my_tell(file,MYF(0));
 
809
    DBUG_PRINT("warning",("info_length: %d  != used_length: %d",
 
810
                          info_length, pos));
 
811
  }
 
812
#endif
 
813
 
 
814
        /* Enlarge files */
 
815
  DBUG_PRINT("info", ("enlarge to keystart: %lu", (ulong) share.base.keystart));
 
816
  if (my_chsize(file,(ulong) share.base.keystart,0,MYF(0)))
 
817
    goto err;
 
818
 
 
819
  if (! (flags & HA_DONT_TOUCH_DATA))
 
820
  {
 
821
#ifdef USE_RELOC
 
822
    if (my_chsize(dfile,share.base.min_pack_length*ci->reloc_rows,0,MYF(0)))
 
823
      goto err;
 
824
#endif
 
825
    errpos=2;
 
826
    if (my_close(dfile,MYF(0)))
 
827
      goto err;
 
828
  }
 
829
  errpos=0;
 
830
  pthread_mutex_unlock(&THR_LOCK_myisam);
 
831
  if (my_close(file,MYF(0)))
 
832
    goto err;
 
833
  my_free((char*) rec_per_key_part,MYF(0));
 
834
  DBUG_RETURN(0);
 
835
 
 
836
err:
 
837
  pthread_mutex_unlock(&THR_LOCK_myisam);
 
838
  save_errno=my_errno;
 
839
  switch (errpos) {
 
840
  case 3:
 
841
    VOID(my_close(dfile,MYF(0)));
 
842
    /* fall through */
 
843
  case 2:
 
844
    /* QQ: T�nu should add a call to my_raid_delete() here */
 
845
  if (! (flags & HA_DONT_TOUCH_DATA))
 
846
    my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_DEXT,
 
847
                                     MY_UNPACK_FILENAME | MY_APPEND_EXT),
 
848
                           MYF(0));
 
849
    /* fall through */
 
850
  case 1:
 
851
    VOID(my_close(file,MYF(0)));
 
852
    if (! (flags & HA_DONT_TOUCH_DATA))
 
853
      my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_IEXT,
 
854
                                       MY_UNPACK_FILENAME | MY_APPEND_EXT),
 
855
                             MYF(0));
 
856
  }
 
857
  my_free((char*) rec_per_key_part, MYF(0));
 
858
  DBUG_RETURN(my_errno=save_errno);             /* return the fatal errno */
 
859
}
 
860
 
 
861
 
 
862
uint mi_get_pointer_length(ulonglong file_length, uint def)
 
863
{
 
864
  DBUG_ASSERT(def >= 2 && def <= 7);
 
865
  if (file_length)                              /* If not default */
 
866
  {
 
867
#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
 
868
    if (file_length >= ULL(1) << 56)
 
869
      def=8;
 
870
    else
 
871
#endif
 
872
    if (file_length >= ULL(1) << 48)
 
873
      def=7;
 
874
    else if (file_length >= ULL(1) << 40)
 
875
      def=6;
 
876
    else if (file_length >= ULL(1) << 32)
 
877
      def=5;
 
878
    else if (file_length >= ULL(1) << 24)
 
879
      def=4;
 
880
    else if (file_length >= ULL(1) << 16)
 
881
      def=3;
 
882
    else
 
883
      def=2;
 
884
  }
 
885
  return def;
 
886
}