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